>[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
}
}
~~~
- TypeSprict -- 了解
- TS-- 搭建(一)webpack版本
- TS -- 搭建(二)直接使用
- TS -- 基本类型
- ts -- 类型推导和字面量类型
- ts -- 类型扩展和类型缩小
- ts -- any场景
- ts -- 使用unknown 还是 any
- ts -- any/never/unknown
- ts -- 断言
- ts -- 类型大小写疑惑
- ts -- 数组类型 [] 还是泛型疑惑
- TS -- 枚举
- 外部枚举
- TS -- 函数
- ts -- 重载作用
- ts -- 05 this is
- 解构
- TS -- 接口
- 绕过接口的多余参数检查
- Interface 与 Type 的区别
- TS -- 类
- ts -- 类作为类型
- TS -- 交叉和联合 类型
- ts -- 交叉类型
- ts -- 联合类型
- ts -- 交叉和联合优先级
- ts -- 类型缩减
- TS -- 什么是泛型
- ts -- 泛型函数表达式/函数别名/接口
- ts -- 泛型类
- ts -- extends 泛型约束
- ts -- 泛型new
- ts -- Ts的泛型
- TS -- 缩小类型详解类型守卫
- TS -- 类型兼容性
- TS -- 命名空间与模块化
- ts -- 模块化
- ts -- 命名空间
- TS -- 工具方法
- Record -- 一组属性 K(类型 T)
- Exclude -- 从联合类型中去除指定的类
- Extract -- 联合类型交集
- NonNullable -- 从联合类型中去除 null 或者 undefined
- Partial -- 将所有属性变为可选
- Required -- 所有属性变为必填
- Readonly -- 所有属性只读
- Pick -- 类型中选取出指定的键值
- Omit -- 去除指定的键值