今天学习了一个新姿势 ! 基本需求是这样的: 要判断一个对象是否含有某个属性, 如果有的话, 调用那个属性进行操作, 在 ts 中, 我们对某个对象进行类型注解, 调用该对象属性时候就会进行类型检查, 如果属性不存在的话就会报错, 为了优雅的解决报错的问题, 就有了底下这个姿势:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const a = {
m: '1',
n: '2'
}

if (hasOwn(a, 'l')) {
const b = a.l
}

function hasOwn<U extends string>(target: any, property: U): target is Record<U, any>{

return target.hasOwnProperty(property)

}
  1. U 继承于 string , 后面使用到 U 这个类型的时候, 如, 传入了一个 property, 类型就会收敛于 string

  2. Record<K, T>
    构造一个类型为 T 的属性 K 的类型

  3. target is Record<U, any> 类型收窄

用底下这个例子来分析:

1
2
3
4
5
6
7
8
9
10
function isFunction(target: any): target is Function {
return typeof target === 'function'
}

// 使用这个函数
if (isFunction(a)) {
// 当 a 为 Function 的时候, 也就是这个函数返回 true 的时候, 就进入了这个控制流
// 此时 ts 会自动判断 a 的类型, 也就是在这里 target is Function
// 这就是类型收窄
}

同上, 分析我们原先的代码, 当调用 hasOwn之后返回值为 true 的时候, target 在控制流里的类型就会表现为上下文中 target 原本的类型 & Record<U, any>