首页 > 解决方案 > Object 和 {} 类型有什么区别,什么时候用哪个

问题描述

他们非常清楚他们的目的是什么。但这并不能满足作为程序员的我。对我来说(我刚开始学习 Type Script,所以这可能是错误的),他们可以也不能做几乎相同的事情。除了你可以实现 Object(仍然怀疑为什么有人需要这样做)但你不能实现 {}。(当然,您也可以只使用 new Object 或调用 Object.keys 之类的东西。但这在这里无关紧要)。

所以对于要编写 TypeScipt 代码的人来说。类型 Object 和 {} 有什么区别。为什么类型 {} 甚至存在?

标签: typescript

解决方案


你不能实现 {}

这是不正确的。这是允许的:

type Empty = {};

class B implements Empty {

}

诚然,它没有多大意义——implements Empty不会为 的用户添加任何信息,B也不会对实现添加任何约束。

为什么类型 {} 甚至存在?

如果你对名为“intersection”和“union”的类型进行操作,你迟早会想要一个类型X,对于任何类型T,满足等价T | X = TT & X = X。这X{}一种被定义为不具有任何属性的类型。它为什么存在?出于同样的原因,存在一个空集。它在哪里有用?当您需要一个具体类型但不确切知道它可能具有哪些属性时,可以在任何地方使用。这是一个例子:

type BaseEventHandlers<Event extends string> = { [event in Event]: {} };
// in BaseEventHandlers we don't know exact type of data that comes with different event types,
// so we have it as {}
// it's better than any because any can have unpredictable effect on type checking
// it's better than Object because Object has properties with names 
// that could possibly interfere with our data


type EventHandlers<H extends BaseEventHandlers<string>> = { [event in keyof H]: (args: H[event]) => void };
// here we can express a constraint that each event handler 
// must receive an object of appropriate type

// example
type UserEvents = {
    user_added: { name: string };
    user_joined_team: { userName: string, teamName: string };
}

const userHandlers: EventHandlers<UserEvents> = {
    // what is checked by the compiler here:
    // all events have handlers assigned
    // each handler has correct names for arguments
    // argument types are inferred from types in `UserEvents` 
    // and do not need to be repeated here
    user_added: ({ name }) => { 

    },
    user_joined_team: ({ userName, teamName }) => {

    }
}

更新

糟糕,事实证明{},以及任何像 的原始类型string,仍然被隐式地认为具有Object- 的所有预定义属性,正如 J.Doe 所指出的那样,这没有错误:

const userHandlers: EventHandlers<UserEvents> = {
    // what is checked by the compiler here:
    // all events have handlers assigned
    // each handler has correct names for arguments
    // argument types are inferred from types in `UserEvents` 
    // and do not need to be repeated here
    user_added: ({ name, toString }) => { 

所以我的回答只是一厢情愿——这就是我想要的,但实际上和{}之间几乎没有区别。它们仍然不同:{}Object

type o = keyof Object; // 'constructor' | 'toString' | ...

type e = keyof {}; // never

但差异是微妙的,我不确定如何在实践中使用它。就个人而言,我更喜欢用{}不带任何属性的类型来表示,Object当我需要参考ObjectJavascript 运行时提供的原型时。string因此,差异主要是名义上的,与和String之间的差异几乎相同。


推荐阅读