刚刚在我的打字本代码库中发现了一个重要的错误,因为这是允许的:
const nums: number[] = { ...[1, 2, 3] } // should have been [ ...[1,2,3] ]
a.join('-')
// runtime error: a.join is not a function 为什么一个数组被解构为一个对象,分配给数组,在那里它可以导致一个很容易预防的运行时异常?
发布于 2020-05-12 01:29:35
这是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};但不幸的是,interface并不是class。因此,当将数组扩展到对象时,编译器认为所有的Array属性和方法都是复制的,因此得到的对象符合Array接口,因此有一个join()方法。奥普西。
如果有人可以更改标准库,那么我们就可以使用interface Array<T>、interface ArrayConstructor和declare var Array: ArrayConstructor,而不是declare class Array<T>,然后join()就不再被看作是可扩展的了,但我不确定。当我在自己的系统上在本地试用时,它似乎很有效,但我无法在游乐场或其他在线IDE中轻松地复制它,而且与Array这样的内置类型混为一谈也不是我喜欢做的事情。
或者可以更改语言,以便在interfaces上标记非自有或不可枚举的属性,但我不指望它(见微软/打字稿#9726)。
目前,这是TypeScript的一个设计限制。如果你对此有强烈的感觉,你可以转到microsoft/TypeScript#34780,给它一个并描述你是如何被它咬的,但我不知道它会有多大的好处。
好吧,希望这能帮上忙,祝你好运!
https://stackoverflow.com/questions/61741437
复制相似问题