【问题标题】:Why is this allowed? const nums: number[] = { ...[1, 2, 3] }为什么允许这样做?常量 nums: number[] = { ...[1, 2, 3] }
【发布时间】:2020-05-11 23:57:30
【问题描述】:

刚刚在我的打字稿代码库中发现了一个严重错误,因为这是允许的:

const nums: number[] = { ...[1, 2, 3] } // should have been [ ...[1,2,3] ]
a.join('-')
// runtime error: a.join is not a function 

Playground

为什么一个数组被解构为一个对象,可以分配给数组,它可以导致一个容易预防的运行时异常?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    这是 TypeScript 的设计限制;见microsoft/TypeScript#34780

    类型系统没有办法将interface 成员标记为“自己的”或可枚举的,因此编译器假定所有成员都通过扩展运算符复制。作为一种启发式方法,这通常是足够的,但是对于原型上设置的任何成员(例如类的方法),它都会做错事:

    interface Whoops {
        foo(): void;
        a: number;
        b: string;
    }
    
    class Oops implements Whoops {
        foo() { }
        a = 1;
        b = "";
    }
    
    const oopsie = (w: Whoops) => ({ ...w });
    
    oopsie(new Oops()).foo(); // no compiler error
    // runtime error: oopsie(...).foo is not a function!
    

    如果您直接编写class 声明,编译器将假定方法声明不可扩展:

    declare class Whoops {
        foo(): void;
        a: number;
        b: string;
    }
    const oopsie = (w: Whoops) => ({ ...w });
    oopsie(new Whoops()).foo(); // compiler time error as expected
    // foo does not exist on {a: number; b: string};
    

    但不幸的是type declarations for Array<T> are for an interface 而不是declared class。因此,当您将数组传播到对象中时,编译器认为所有Array 属性和方法都被复制,因此生成的对象符合Array 接口,因此具有join() 方法。哎呀。


    Maaaaybe 有人可以更改标准库,以便我们不再将 interface Array<T>interface ArrayConstructordeclare var Array: ArrayConstructor 改为 declare class Array<T>,然后 join() 将不再被视为可传播的,但我不是当然。当我在自己的系统上本地尝试时,它似乎可以工作,但我无法在 Playground 或其他在线 IDE 中轻松地重现它,并且弄乱像 Array 这样的内置类型并不是我喜欢做的事情.

    或者可以更改语言,以便可以在interfaces 上标记非自己或不可枚举的属性,但我不会指望它(请参阅microsoft/TypeScript#9726

    目前这是 TypeScript 的设计限制。如果你对此有强烈的感觉,你可以去 microsoft/TypeScript#34780 并给它一个 ? 并描述你是如何被它咬的,但我不知道它真的有多大好处。

    好的,希望对您有所帮助;祝你好运!

    Playground link to code

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-17
      • 2011-10-14
      • 1970-01-01
      • 2013-09-07
      • 1970-01-01
      • 2020-05-01
      • 2017-02-24
      • 1970-01-01
      相关资源
      最近更新 更多