对象和 {} 类型有什么区别,何时使用哪个



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

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

你无法实现 {}

这根本不是真的。这是允许的:

type Empty = {};
class B implements Empty {
}

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

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

如果你对名为"交集"和"并集"的类型有操作,你迟早会希望有一个类型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当我需要引用 Javascript 运行时提供的Object原型时。所以差异主要是名义上的,与stringString之间的差异几乎相同。

最新更新