这是 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 ArrayConstructor 和 declare var Array: ArrayConstructor 改为 declare class Array<T>,然后 join() 将不再被视为可传播的,但我不是当然。当我在自己的系统上本地尝试时,它似乎可以工作,但我无法在 Playground 或其他在线 IDE 中轻松地重现它,并且弄乱像 Array 这样的内置类型并不是我喜欢做的事情.
或者可以更改语言,以便可以在interfaces 上标记非自己或不可枚举的属性,但我不会指望它(请参阅microsoft/TypeScript#9726)
目前这是 TypeScript 的设计限制。如果你对此有强烈的感觉,你可以去 microsoft/TypeScript#34780 并给它一个 ? 并描述你是如何被它咬的,但我不知道它真的有多大好处。
好的,希望对您有所帮助;祝你好运!
Playground link to code