type k<T> = T extends U ? X : Y T 如果可以分配 给 U 则返回 X 否则返回 Y
实例:type k<T> = T extends number ? string : boolean
可以通过下面这样的条件来筛选联合类型
type a = string | number
type k = T extends string ? never : T
type b = k // number
推断 infer :只能使用在条件类型中 type k<T> = T extends infer R ? R : boolean 这里使用推断返回了 T 自身,但 infer 更多的是用于获取 T 中的某一部分的类型,例如 T 是一个函数的时候 type k<T> = T extends (...arg)=>infer R ? R : T 这里利用 infer 获取 T 的返回值的类型
类型保护 缩小类型范围(我认为这样描述更形象贴切)
in , typeof , instanceof 这三个操作符 ts 都可以自动推断排除操作结果为假的类型
typescript
if("swim" in pet){// 还可以改成 pet.swim ,typeof 也有缩小类型范围的功能
// 在这个范围内 pet 的类型被确认为 Fish 了
}
自定义类型保护:
typescript
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
const opType = 'create' as 'create' | 'updated'
if (opType === 'create') {
// create....
} else if (opType === 'updated') {
// updated....
} else {
opType satisfies never
}
const opTypeNew = 'create' as 'create' | 'updated' | 'delete'
if (opTypeNew === 'create') {
// create....
} else if (opTypeNew === 'updated') {
// updated....
} else {
// 这里就会报错
// 每次在穷举所有可能性的时候在最后的分支使用这种技巧可以使得当我们遗漏了某些情况的时候会提示我们
// Type '"delete"' does not satisfy the expected type 'never'.
opTypeNew satisfies never
}
一个函数具有不同入参类型的最佳实践
ts
/** 更新数据 */
function fn(op:'updated',id:number):any
/** 创建数据 */
function fn(op:'created'):any
/** 如果在上面的重载写了 jsdoc 那么这里的 jsdoc 将无法看到
* 使用这种形式相比下面这种更常见的我感觉类型描述更准确一些
* 并且上面两个重载声明也可以直接不用(但如果要针对不同重载写 jsdoc 的话还是要有重载声明的)
* ```ts
* function fn(op:'created'|'updated',id?:number){}
* ```
*/
function fn(...[op,id]:['created']|['updated',number]){
}
fn('created')
fn('created',1) //Argument of type '"created"' is not assignable to parameter of type '"updated"'.
fn('updated') //Argument of type '"updated"' is not assignable to parameter of type '"created"'.(2345)
fn('updated',1)