想象一下,我们有界面
interface Foo {
bar: number | undefined;
}
如果我们尝试创建类型为Foo的对象
const foo: Foo = {};
它不会编译,因为缺少属性栏。但是我们说它可以是未定义的,如果我们明确地将它设置为未定义,它将起作用,但如果我们根本不设置它就完全相同。它不应该跟下面完全相同吗?
interface Foo {
bar?: number;
}
对我来说这是一个问题,因为如果我们考虑更复杂的例子,我们有一个字段的接口,这可以是泛型类型的可选。因此,如果未指定泛型类型,则字段应该是未定义的,如果已指定,则它应该只是该类型。例如
interface Foo<T = undefined> {
bar: T;
title: string;
}
const foo1: Foo = {
title: 'TITLE'
};
const foo2: Foo<number> = {
title: 'title',
bar: 12
};
foo1将无法编译,因为缺少属性,但无论如何它必须是未定义的,如果我们明确指定它将起作用,但这完全相同。 我最终用继承来解决这个问题,其中基类没有任何通用参数,并且子项严格指定了它。但我很好奇是否有人知道为什么这种方式处理未定义类型的具体原因。因为我自己无法找到任何相关信息。
答案 0 :(得分:6)
这两种类型的签名并不完全相同(虽然它们足够接近,乍看之下差异可能不明显)!
bar?: number
表示该对象可能没有名为bar
的字段。bar: number | undefined
表示该对象始终有一个名为bar
的字段,但该字段的值可能设置为undefined
。在某些情况下,这种差异可能很重要,因为某些运行时行为依赖于存在的字段与设置为未定义的字段之间的差异 - 请考虑是否在对象上调用Object.keys
:
Object.keys({ bar: undefined }) // returns ["bar"]
Object.keys({}) // returns []
答案 1 :(得分:4)
原因似乎是没有人实施过它。实现当前类型检查器的方式最终要求需要undefined
类型的属性,但有一个proposal以更有意义的方式更改行为,但没有人得到它呢。
使用条件类型可以实现为类型保持相同名称并使字段可选的变通方法:
type Foo<T = undefined> = {
title: string;
} & (T extends undefined ? {} : { bar: T});
const foo1: Foo = {
title: 'TITLE'
};
const foo2: Foo<number> = {
title: 'title',
bar:10
};