TypeScript的控制流分析让你从一个更广泛的类型缩小到一个更狭窄的类型。
function print(msg: any) {
if(typeof msg === 'string') {
// We know msg is a string
console.log(msg.toUpperCase()) // 👍
} else if (typeof msg === 'number') {
// I know msg is a number
console.log(msg.toFixed(2)) // 👍
}
}
这是JavaScript中的一个类型安全检查,TypeScript也从中受益。然而,在写这篇文章的时候,有些情况下TypeScript需要我们提供更多的帮助。
让我们假设你有一个JavaScript对象,你不知道某个属性是否存在。该对象可能是any 或unknown 。在JavaScript中,你会检查这样的属性。
if(typeof obj === 'object' && 'prop' in obj) {
//it's safe to access obj.prop
console.assert(typeof obj.prop !== 'undefined')
// But TS doesn't know :-(
}
if(typeof obj === 'object' && obj.hasOwnProperty('prop')) {
//it's safe to access obj.prop
console.assert(typeof obj.prop !== 'undefined')
// But TS doesn't know :-(
}
目前,TypeScript还不能用prop 来扩展obj 的类型。尽管这在JavaScript中是可行的。
然而,我们可以写一个小的辅助函数来获得正确的类型。
function hasOwnProperty<X extends {}, Y extends PropertyKey>
(obj: X, prop: Y): obj is X & Record<Y, unknown> {
return obj.hasOwnProperty(prop)
}
如果你不想知道这是如何工作的,复制它并感到高兴。如果你想知道更多,让我们来看看发生了什么。
- 我们的
hasOwnProperty函数有两个泛型。X extends {}确保我们只在对象上使用这个方法Y extends PropertyKey确保键是 。 是一个内置的类型。string | number | symbolPropertyKey
- 没有必要明确地定义泛型,它们是通过用法推断出来的。
(obj: X, prop: Y):我们想检查prop是否是一个属性键的obj- 返回类型是一个类型谓词。如果该方法返回
true,我们可以重新输入我们的任何参数。在这种情况下,我们说我们的obj是原始对象,其交集类型为Record<Y, unknown>,最后一块将新发现的属性添加到obj并将其设置为unknown。
在使用中,hasOwnProperty ,就像这样工作。
// person is an object
if(typeof person === 'object'
// person = { } & Record<'name', unknown>
// = { } & { name: 'unknown'}
&& hasOwnProperty(person, 'name')
// yes! name now exists in person 👍
&& typeof person.name === 'string'
) {
// do something with person.name, which is a string
}