为什么';t typescript未定义类型的行为是否与可选类型相同?

为什么';t typescript未定义类型的行为是否与可选类型相同?,typescript,Typescript,假设我们有接口 interface Foo { bar: number | undefined; } 如果我们尝试创建Foo-like类型的对象 const foo: Foo = {}; 它将无法编译,因为缺少属性栏。但是我们说它可以是未定义的,如果我们显式地将它设置为未定义,这将起作用,但是如果我们根本不设置它,这是完全相同的。它不应该和下面一样吗 interface Foo { bar?: number; } 对于我来说,这是个问题,因为如果我们考虑更复杂的例子,在那里我们有

假设我们有接口

interface Foo {
  bar: number | undefined;
}
如果我们尝试创建Foo-like类型的对象

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
};
接口Foo{
棒:T;
标题:字符串;
}
常量foo1:Foo={
标题:“标题”
};
常量foo2:Foo={
标题:“标题”,
酒吧:12
};
foo1将无法编译,因为缺少属性,但无论如何它都必须是未定义的,如果我们显式指定它,它将工作,但这是完全相同的。
我最终通过继承解决了这个问题,基类没有任何泛型参数,子类严格指定了它。但我只是好奇,是否有人知道以这种方式处理未定义类型的具体原因。因为我自己找不到关于它的任何信息。

这两种类型的签名并不完全相同(尽管它们非常接近,乍一看差异可能并不明显)

  • bar?:number
    表示对象可能没有名为
    bar
    的字段
  • bar:number | undefined
    表示对象将始终具有名为
    bar
    的字段,但该字段的值可能设置为
    undefined

这种差异在某些情况下可能是重要的,因为一些运行时行为依赖于存在的字段和被设置为未定义的字段之间的差异。

Object.keys({ bar: undefined }) // returns ["bar"]
Object.keys({})                 // returns []

简单的原因似乎是还没有人实施它。当前类型检查器的实现方式最终要求需要类型
undefined
的属性,但有一种方法可以以更合理的方式更改行为,但还没有人做到这一点

可以使用条件类型实现保持类型名称相同并使字段可选的变通方法:

type Foo<T = undefined> = {
    title: string;
} & (T extends undefined ? {} : { bar: T});

const foo1: Foo = {
    title: 'TITLE'
};

const foo2: Foo<number> = {
    title: 'title',
    bar:10
};
类型Foo={
标题:字符串;
}&(T扩展未定义?{}:{bar:T});
常量foo1:Foo={
标题:“标题”
};
常量foo2:Foo={
标题:“标题”,
酒吧:10
};

我知道您并不是在寻找替代解决方案(您提到您是通过继承来解决的),但您也可以通过条件类型来解决它:
type Foo={title:string;}&(T extends undefined?{}:{bar:T})
并为具有类型参数的版本和不具有类型参数的版本保留相同的名称。为什么我不确定的问题。请参阅可能重复的Btw,它看起来像是在问题被问到和TS的当前版本之间的某个时间发生了变化。上面包含的示例为我编译