🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[success] # 类型守卫 ~~~ 1.类型守卫的作用在于触发类型缩小。实际上,它还可以用来区分类型集合中的不同成员 2.类型守卫包括switch、字面量恒等、typeof、instanceof、in 和自定义类型守卫 简单说当一个类型是多种可能时例如'any','unknown','联合类型' 等在逻辑判断时候要具体到其唯一子集可能性 2.1.类型判断:typeof 2.2.实例判断:instanceof 2.3.属性判断:in 2.4.字面量相等判断:==, ===, !=, !== ~~~ >[danger] ##### 没有使用类型守卫案例 ~~~ 1.通过断言,断言其子类型做到缩小范围不报错,虽然这种形式也可以但是需要大量断言来区分类型 ~~~ ~~~ const getRandomValue = (list: (string | number)[]) => { const randomNumber = Math.random() * 10 if (randomNumber > 5) return list[0] else return list[1] } const item = getRandomValue([1, 'w']) // 直接这些写会报错 // 首先第一个问题是返回值的类型不确定是字符还是数字 // 数字是没有length 属性的所以这么写的判断ts 会报错的 // if(item.length){ // console.log(item.length) // }else{ // console.log(item.toFixed()) // } // 解决第一种使用类型断言 // 缺点 每一个item 都要使用对应的类型断言 if ((item as string).length) { console.log((item as string).length) } else { console.log((item as number).toFixed()) } ~~~ >[danger] ##### 使用typeof 进行类型守卫 ~~~ 1.type of ,但只能针对"number","string","boolean"或"symbol",反过来,当联合类型的成员不可枚举, 比如说是字符串、数字等原子类型组成的集合,这个时候就需要使用 typeof。 2.下面案例为例'判断了string'类型else 自动判断就是,number 类型,如果是判读是非这四种类型,else 还需要要自己处理 3.下面代码如果'return params.length ? params.length : params 这么写会报错' 这就是为什么要类型守卫缩小类型 ~~~ ~~~ function getType(params: string | number) { // return params.length ? params.length : params 这么写会报错 if (typeof params === 'string') { return params.length } else { return params } } ~~~ >[danger] ##### instanceof 针对类 -- 缩小范围 ~~~ 1.如果是类的话使用 'instanceof' ~~~ ~~~ class Dog { wang = 'wangwang' } class Cat { miao = 'miaomiao' } const getName = (animal: Dog | Cat) => { if (animal instanceof Dog) { return animal.wang } else (animal instanceof Cat) { return animal.miao } } const cat = new Cat() getName(cat) ~~~ >[danger] ##### 字面量恒等 ~~~ 1.如果是字面量这种联合类型可以使用具体值去比较 2.也可用switch 来缩小类型 代替if ~~~ ~~~ function getType(params: 'a' | 1) { if (params === 'a') { return params.length } return params } ~~~ * 案例二 ~~~ type Foo = { kind: 'foo'; // 字面量类型 foo: number; }; type Bar = { kind: 'bar'; // 字面量类型 bar: number; }; function doStuff(arg: Foo | Bar) { if (arg.kind === 'foo') { console.log(arg.foo); // ok console.log(arg.bar); // Error } else { console.log(arg.foo); // Error console.log(arg.bar); // ok } } ~~~ >[danger] ##### 获取value 值 -- in ~~~ 1.不能直接通过'. '操作符获取 对象值 需要 用 in ~~~ ~~~ type Info = { name: string age: number } type Person = { name: string } function getName(info: Info | Person) { // if(info.age){} // 报错 if ('age' in info) { return info.age } else { return info.name } } ~~~ >[danger] ##### 自定义守卫 -- is ~~~ 1.往往开发时候会吧一些判单同一封装 像下面的例子虽然封装了,但实际效果却报错 function isString(params: unknown) { return typeof params === 'string' } function getName(params: number | string) { // if(typeof params === "string") 可以的但是这种重复逻辑一般会封装 if (isString(params)) { return params.length // 报错 } } ~~~ * 正确写法 ~~~ 1.这里的is 可以是任意类型,可以是自己定义的接口类型,这里是因为需求是string 类型,如果不做 is 类型, TS 只能推断出 isString 是一个返回布尔值的函数,而并不知道这个布尔值的具体含义'{形参} is {类型} 的语法结构' ~~~ ~~~ function isString(params: unknown) :params is string{ return typeof params === 'string' } function getName(params: number | string) { // if(typeof params === "string") 可以的但是这种重复逻辑一般会封装 if (isString(params)) { return params.length } } ~~~