为什么打字稿将object.hasOwnProperty(“ key”)与object中的“ key”本质上不同

时间:2019-12-05 12:24:20

标签: typescript

declare const action: { total: number } | { };
declare const defavlt: 200;

const total = (action.hasOwnProperty("total")) ? action.total : defavlt;

导致action.total的以下TS错误:

Property 'total' does not exist on type '{ type: "NEW_CONVERSATION_LIST" | "UPDATE_CONVERSATION_LIST_ADD_BOTTOM" | "UPDATE_CONVERSATION_LIST_ADD_TOP"; list: IDRArray<RestConversationMember>; total: number | undefined; } | ... 13 more ... | { ...; }'.
  Property 'total' does not exist on type '{ type: "UPDATE_URL_STATE"; updateObj: IMessagingUrlState; }'.ts(2339)

const total = ("total" in action) ? action.total : defavlt

有效。 TS区别对待这两种情况是否有道理?

1 个答案:

答案 0 :(得分:4)

在问题microsoft/TypeScript#10485中,建议in运算符充当type guard,可用于过滤并集;这是在microsoft/TypeScript#15256released with TypeScript 2.7中实现的。

Object.prototype.hasOwnProperty()尚未完成;如果您对此确实有强烈的想法,则可能需要file a suggestion,注意similar suggestion (microsoft/TypeScript#18282)被拒绝是因为它要求对 key 进行更有争议的缩小不是 object ...,有些人想要both (microsoft/TypeScript#20363)。并且不能保证该建议会被接受。

幸运的是,您不必等待此操作在上游实现。与in之类的运算符不同,hasProperty()方法只是一个库签名,可以对其进行更改以充当user-defined type guard函数。此外,您甚至不必触摸standard library definition;您可以使用declaration merging通过您自己的Object签名来扩展hasOwnProperty()界面:

// declare global { // need this declaration if in a module
interface Object {
  hasOwnProperty<K extends PropertyKey>(key: K): this is Record<K, unknown>;
}
// } // need this declaration if in a module

此定义表示,当您检查obj.hasOwnProperty("someLiteralKey")时,true结果意味着obj可分配给{someLiteralKey: unknown},而false结果却没有。该定义可能并不完美,并且可能存在很多边缘情况(例如obj.hasOwnProperty(Math.random()<0.5?"foo":"bar")意味着什么?obj.hasOwnProperty("foo"+"bar")意味着什么?它们将做出奇怪的事情),但是它适用于您的示例:< / p>

const totalIn = ("total" in action) ? action.total : defavlt; // okay
const totalOwnProp = (action.hasOwnProperty("total")) ? action.total : defavlt; // okay

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

Link to code