typescript - 为什么允许这样做?常量 nums: number[] = { ...[1, 2, 3] }
问题描述
刚刚在我的打字稿代码库中发现了一个严重错误,因为这是允许的:
const nums: number[] = { ...[1, 2, 3] } // should have been [ ...[1,2,3] ]
a.join('-')
// runtime error: a.join is not a function
为什么一个数组被解构为一个对象,可以分配给数组,它可以导致一个容易预防的运行时异常?
解决方案
这是 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};
但不幸的是,类型声明Array<T>
是针对 aninterface
而不是声明为class
。因此,当您将数组传播到对象中时,编译器认为所有Array
属性和方法都被复制,因此结果对象符合Array
接口,因此具有join()
方法。哎呀。
Maaaaybe 有人可以更改标准库,而不是interface Array<T>
and interface ArrayConstructor
anddeclare var Array: ArrayConstructor
我们刚刚拥有declare class Array<T>
, 然后join()
将不再被视为可传播的,但我不确定。Array
当我在自己的系统上本地尝试它时,它似乎可以工作,但我无法在 Playground 或其他在线 IDE 中轻松重现它,并且无论如何我都不愿意使用内置类型。
或者 maaaaybe 可以更改语言,以便可以在 s 上标记非自己或不可枚举的属性interface
,但我不会指望它(参见microsoft/TypeScript#9726)
目前这是 TypeScript 的设计限制。如果你对此有强烈的感觉,你可以去 microsoft/TypeScript#34780 并给它一个并描述你是如何被它咬的,但我不知道它真的有多大好处。
好的,希望有帮助;祝你好运!
推荐阅读
- javascript - 数据表日期时间提取分钟并添加 CSS 类
- jmeter - 有没有办法识别发送 200 状态代码但重定向到显示 404 错误的页面的 http 请求
- azure-cosmosdb - 我可以获取 Cosmos DB 表中大量记录的所有记录的计数吗?
- pointers - go - 修改指向切片的指针不会修改原始指针
- java - 在视图之间导航后,组件未正确加载
- php - 使用没有数据库的身份验证登录
- node.js - Angular 前端不会立即更新
- java - 在个人资料活动中滚动查看
- html - 下拉菜单在点击前消失
- docker - kube-proxy 问题 - 尝试将 Windows 工作节点添加到 kubernetes 集群