gpt4 book ai didi

typescript - 为什么这是允许的?常数 nums : number[] = { . ..[1, 2, 3] }

转载 作者:行者123 更新时间:2023-12-04 10:03:01 25 4
gpt4 key购买 nike

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

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

Playground

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

最佳答案

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

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

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接口(interface),因此有一个 join()方法。糟糕。


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

或者 maaaaybe 可以更改语言,以便可以在 interface 上标记非拥有或不可枚举的属性。 s,但我不会指望它(参见 microsoft/TypeScript#9726 )

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

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

Playground link to code

关于typescript - 为什么这是允许的?常数 nums : number[] = { . ..[1, 2, 3] },我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61741437/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com