【问题标题】:How to type check spread operator in Typescript?如何在 Typescript 中键入检查扩展运算符?
【发布时间】:2020-10-19 23:36:00
【问题描述】:

有没有办法让它不编译? (因为它确实......)

const bar: { a: string } = {
    a: '',
    ...{b: ''}
}

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    我震惊地发现它通过了类型检查器!

    经过一番探索,我对为什么会发生这种情况有一种强烈的预感,但我还没有找到任何官方消息来支持它。 因此,这不是一个答案,而是一个对于评论来说太长的对话启动器。 就是这么说,接下来的事情要持保留态度。

    我怀疑 TypeScript 的“归属”/“注释”机制允许基于子类型的一些回旋余地。 具体来说,当我们写:

    const foo: Foo = bar;
    

    只要bar 的类型是Foo子类型,这似乎就能顺利通过检查。 这是一个具体的例子:

    class Foo {
      public a: string;
    }
    
    // `Bar` is a subtype of `Foo`
    class Bar extends Foo {
      public b: string;
    }
    
    const foo: Foo = new Bar();
    //         ^^^       ^^^ This is just fine!
    

    此外,由于 TypeScript 的子类型概念是“结构化的”,因此以下内容也是完全可以接受的:

    class Foo {
      a: string;
    }
    
    // `Quux` is structurally the same as (and therefore a subtype of) `Foo`
    class Quux {
      a: string;
    }
    
    const foo: Foo = new Quux();
    

    考虑到这个[理论],检查器会接受您的示例,因为{ a: string; b: string }{ a: string } 的子类型。

    总之,如果这是正确的,我认为没有办法诱使类型检查器拒绝您的示例。

    编辑:这不是完整的故事。 正如@apflieger 指出的那样,这个理论并不能解释原因

    const foo: { a: string } = {
      a: 'test',
      b: 'test',
    };
    

    被拒绝。 看起来传播在这里很关键。

    可能是那种

    {
      a: 'test',
      ...{ b: 'test' }
    }
    

    推断为{ a: string } & { b: string },而在前一种情况下推断为{ a: string; b: string }

    【讨论】:

    • 对于类,是的,但对于原始接口,这令人惊讶。在我没有展开运算符的示例中,它不会编译: const foo: {a: string} = {a: '', b: ''} // 失败
    • 这是一个很好的观点。这显然取决于您是否传播{ b: '' }
    猜你喜欢
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 2018-05-15
    • 2023-02-25
    • 2021-10-24
    • 1970-01-01
    • 2019-02-04
    相关资源
    最近更新 更多