他们非常清楚地表明了他们的目的是什么。但这并不能满足我作为一个程序员。对我来说(我刚刚开始学习类型脚本,所以这可能是错误的(,他们可以和不能做几乎同样的事情。除了你可以实现 Object(仍然怀疑为什么有人需要这样做(,但你不能实现 {}。(当然,你也只能新建 Object 或调用 Object.keys 之类的东西。但这在这里无关紧要(。
所以对于那些要编写TypeScipt代码的人。对象和{}类型有什么区别。为什么类型 {} 甚至存在?
你无法实现 {}
这根本不是真的。这是允许的:
type Empty = {};
class B implements Empty {
}
当然,这没有多大意义 -implements Empty
不会为B
的用户添加任何信息,也不会对实现添加任何约束。
为什么类型 {} 甚至存在?
如果你对名为"交集"和"并集"的类型有操作,你迟早会希望有一个类型X
,对于任何类型T
,满足等价T | X = T
和T & 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
原型时。所以差异主要是名义上的,与string
和String
之间的差异几乎相同。