如何避免enumerable:false属性的编译器错误



我正在尝试学习TS,但遇到了一个奇怪的情况。

我有一个属性设置为不可枚举的对象:

let person = {
name: 'Harry'
}
Object.defineProperty(person,'salary',{enumerable: false, value : 15});
console.log(person.salary); // 15

这在运行时有效,但是,编译器会出错:

类型"{name:string;}"上不存在属性"salary">

这是预期的。

我可以绕过这种设置——任何类型的人都可以,但这感觉不是一个干净的解决方案。

还有别的办法吗?非null断言运算符对此不起作用。

如果有人能分享一些这方面的知识,我将不胜感激。

虽然您可以更改person的类型注释,可能类似于:

let person: { name: string; salary?: number } = {
name: 'Harry'
};

甚至:

let person = {
name: 'Harry'
} as { name: string; salary: number };

最安全的方法可能是(ab(在版本3.7:中使用断言函数

function defineProperty<
O,
Property extends PropertyKey,
Value
>(o: O, key: Property, attributes: PropertyDescriptor & ThisType<any> & { value: Value }): asserts o is O & Record<Property, Value> {
Object.defineProperty(o, key, attributes);
}

它本质上是Object.defineProperty的包装函数,告诉TypeScript,如果该函数没有抛出错误,则给定值o的类型为O & Record<Property, Value>

所以当你使用它时,你会得到这样的类型:

defineProperty(person,'salary',{enumerable: false, value : 15});
person
// ^? { name: string; } & Record<"salary", number>

游乐场


如果真的想,你也可以通过将断言更改为来使结果类型更干净

asserts o is (O & Record<Property, Value> extends infer T extends O ? { [K in keyof T]: T[K] } : O)

当您将鼠标悬停在person上时,您可以在这里看到,类型现在是{ name: string; salary: number; },而不是难看的交集。

相关内容

最新更新