is
关键字
TypeScript使用is
关键字来实现类型保护
举一个简单的例子:
此时的val提示的属性和方法是any
但如果给isNumbre
这个方法加上is
关键字,就可以起到类型保护的作用
此时的val提示的属性和方法是number
了。
keyof
关键字
TypeScript
允许我们遍历某种类型的属性,并通过keyof
操作符提取其属性的名称。- 该操作符可以用于获取某种
类型
的所有键,其返回类型是联合类型
,简单的说,它是作用于类型的,返回类型为联合类型。
1.作用 interface
或type
作用 interface
或type
类型时 keyof
将对象中的属性名都结构出来,并作为联合类型返回。
interface User {
id: string
name: string
addr: string[]
}
type U1 = keyof User
// type U1 = 'id' | 'name'| 'addr'
2.作用于数组时
作用于数组时,将数组对应的属性全部作为联合类型返回。
type T1 = keyof []
// T1 = 'length' | 'concat' | 'splice' | ...
3. 作用于类时
作用于类时,将类生成的对象属性和方法,当联合类型返回。
4. 作用于any
直接看代码
type T1 = keyof any
// type T1 = 'string' | 'number' | 'symbol'
应用
typeof
关键字
1. 获取对象的类型:
2. 在枚举中使用
3. 函数
function add(a: number, b:number) {
return a + b
}
type AddType = typeof add
extends
关键字
extends
关键字,在不同的场景有不同的用法:
- 表示继承/拓展的含义
- 表示约束的含义
- 表示分配的含义、
1. 继承
interface Pet {
name: string
age: number
}
interface Cat extends Pet {
miao(): void
}
interface Dog extends Pet {
wang(): void
}
const cat: Cat = {
name: '悠米',
age: 2,
miao() {
console.log(`喵喵`)
}
}
const dog: Dog = {
name: '旺财',
age: 2,
wang() {
console.log(`汪汪`)
}
}
2. 泛型约束
在书写泛型的时候,我们往往需要对类型参数作一定的限制,比如希望传入的参数都有 name 属性的数组我们可以这么写:
function sayHello<T extends {name: string}>(t: T) {
console.log(`我是${t.name}`)
}
interface Student {
name: string
age: number
}
const stu1: Student = {
name:'小明',
age: 12
}
sayHello(stu1)
3. 条件分发
extends
的第三种用法就是用来判断一个类型是不是可以分配给另一个类型,这在写高级类型的时候非常有用。
3.1 作为条件判断
interface Animal {
name: string
}
interface Bird {
name: string
fly(): void
}
// 这里表示 T2类型是否可以分配给T1类型,根据类型提示是“YES”
type MyT = Bird extends Animal ? "YES" : "NO"
3.2 联合类型分配
比如有如下类型:
interface Fish {
name:string
type: '鱼'
}
interface Bird {
name:string
type: '鸟'
}
interface Swiming {
swiming: string
}
interface Sky {
sky: string
}
type MyType<T> = T extends Bird ? Sky : Swiming
然后给T传递一个联合类型,如下:
type IEnv = MyType<Fish | Bird>
那么:
type IEnv = Fish extends Bird ? Sky : Swiming | Bird extends Bird ? Sky : Swiming
所以:
type IEnv = Swiming | Sky
infer
关键字
TypeScript
中的infer
具有推断类型变量的作用
来看一下内置ReturnType
的实现:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
内置类型实现
Exclude
先来看用法,就是在一个类型中排除某些个类型
type MyType = Exclude<string | number | boolean, boolean>
// 此时 type MyType = string | number
思路:
type MyExclude = (string extends boolean ? never : string) |
( number extends boolean ? never : number) |
(boolean extends boolean ? never : boolean)
那么,Exclude
的实现就是:
type MyExclude<T, U> = T extends U ? never : T
Extract
先来看用法,就是在一个类型中抽离某些个类型,跟Exclude相反
type T = Exclude<string | number | boolean, boolean>
// 此时 type MyExclude = boolean
实现
type MyExtract<T, U> = T extends U ? U : never
Pick
就是从一个复合类型中,取出几个想要的类型的组合,如下:
interface User {
id: string
name: string
age: number
addr: string[]
}
// 我只想要 id和name两个属性的类型,
type MyUser = Pick<User,'id' | 'name'>
那么,如何实现该类型呢?
- 首先,要了解到
TypeScript
是如何遍历联合类型的。语法就是[P in T]
:
-
TypeScript
是如何根据类型的key获取类型的,语法就是T['key']
,比如下面要获取User的id类型 -
还有,
Pick
的第二个泛型参数需要进行类型约束,K extends keyof T
那么Pick
的实现,就很简单了:
type MyPick<T, K extends keyof T> = {
[P in K]: T[P]
}
Omit
Omit
的作用和Pick
相反,就是从一个复合类型中,剔除几个不想要的类型的组合,如下:
既然和Pick
相反,那么我们就是要从id | name | age | addr
中剔除id | name
。可以利用前面的Exclude
:
type T1 = Exclude<keyof User, 'id'|'name'>
// type T1 = age | addr
那么Omit
的实现,就很简单了:
type MyOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
Record
用于属性映射:
interface PageInfo {
title: string;
}
type Page = "home" | "about" | "contact";
const nav: Record<Page, PageInfo> = {
about: { title: "about" },
contact: { title: "contact" },
home: { title: "home" },
};