ts中类型的优先级
1、any、unknown 即顶级类型
2、Object
3、Number、String、Boolean
4、number、string、boolean
5、123、'123'、false
6、nerver
unknown类型的数据,只能赋值给自身或者是any
unknown类型的数据,无法获取对象中的属性或者是方法
never类型的数据,表示不应该存在或者永远无法达到的状态数据类型(很抽象呀)
// 没有一个数据既是number类型又是string类型,所以a的类型既是never
type a = number & string
// 在联合类型中,never类型由于是最底层的类型,会被ts自动忽略,所以a的类型既是number | void
type a = number | void | never
any、unknown、never 的区别是什么?- any、unknown是顶级类型,任何类型的值都可以赋值给顶级类型变量
- 但是 unknown 比 any 的类型检查更严格,any 什么检查都不做,unknown 要求先收窄类型:
- 所以能用 unknown 就优先用 unknown,类型更安全一点
const value: unknown = "Hello World";
const someString: string = value; // 报错:Type 'unknown' is not assignable to type 'string'.(2322)
Record【用于属性映射】
Record的内部定义,接收两个泛型参数;Record后面的泛型就是对象键和值的类型
作用 :定义一个对象的 key 和 value 类型,即同时约束key 和 value
源码:
type Record<K extends keyof any, T> = {
[P in K]: T
}
// keyof any ===> 就是 string | number | symbol 的联合类型
Record<string, never>空对象
Record<string, unknown>任意对象
{}任何不为空的对象
type Record<K extends string | number | symbol, T> = {
[P in K]: T;
}
逐步解析
泛型K即为第一次参数
p in xx 又是什么意思呢?
in的意思就是遍历,如上就是将 类型string进行遍历,也就是string
每个属性都是传入的T类型,如 string: PersonModel
使用 Record 例子
type Person = {
name:string
age: number
}
type K = 'A' | 'B'
type FinalPerson = Record<K, Person>
let obj:FinalPerson = {
A:{name:'张三', age:18},
B:{name:'李四', age:28}
}
Partial【部分的; 不完全的】
源码:
type Partial<T> = {
[P in keyof T]?: T[P]
}
作用:生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为可选项
使用 Partial 例子
interface Foo {
name: string
age: number
}
type Bar = Partial<Foo>
// 相当于
type Bar = {
name?: string
age?: number
}
type PartialPerson = Partial<Person>;
const partialPersonInstance: PartialPerson = {
name: '12',
// 或者只有age属性, 或者两个属性都不存在
};
// partial的内部定义
type MyPartial<T> = {
[K in keyof T]?: T[K]
}
Required【必须的 意思是将一个定义中的属性全部变成必选参数】
源码:
type Require<T> = {
[p in keyof T]-?: T[P]
}
作用:生成一个新类型,该类型与 T 拥有相同的属性,但是所有属性皆为必选项
使用 Required 例子
interface Foo {
name: string
age?: number
}
type Bar = Required<Foo>
// 相当于
type Bar = {
name: string
age: string
}
Readonly【让一个定义中的所有属性都变成只读参数】
源码:
type Readonly<T> = {
[p in keyof T]-?: T[P]
}
作用:生成一个新类型,T 中的 K 属性是只读的,K 属性是不可修改的。
interface Foo {
name: string
age: number
}
type Bar = Readonly<Foo>
// 相当于
type Bar = {
readonly name: string
readonly age: string
}
使用 Readonly 例子
type ReadOnlyPerson = Readonly<Person>;
const readPersonInstance: ReadOnlyPerson = {
name: '123',
age: 20,
};
// readPersonInstance.name = '234'; // error
Pick【从类型定义的属性中,选取指定一组属性,返回一个新的类型定义】
源码:
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
作用:生成一个新类型,该类型拥有 T 中的 K 属性集 ;
新类型 相当于 T 与 K 的交集
使用场景:主要是从一个已知的类型中,取出子集,作为一个新的类型返回
interface Foo {
name: string;
age?: number;
gender: string;
}
type Bar = Pick<Foo, 'age' | 'gender'>
// 相当于
type Bar = {
age?: number
gender: string
}
const todo: Bar= {
age?: 3,
gender: 男
};
console.log(todo)
使用 Pick 例子
Partial 【部分的,不完全的,可选的】
源码:
type Partial<T> = {
[P in keyof T]?: T[P]
};
作用:
keyof T拿到T所有属性名,然后in进行遍历,将值赋给 P,最后T[P]取得相应属性的值
使用 Partial 例子
type PartialPerson = Partial<Person>;
const partialPersonInstance: PartialPerson = {
name: '12',
// 或者只有age属性, 或者两个属性都不存在
};
// partial的内部定义
type MyPartial<T> = {
[K in keyof T]?: T[K]
}
Exclude【排除"联合类型" 中一部分的内容】
源码:
type Exclude<T, U> = T extends U ? never : T
作用:如果 T 是 U 的子类型则返回 never 不是则返回 T
type A = number | string | boolean
type B = number | boolean
type Foo = Exclude<A, B>
// 相当于
type Foo = string
使用 Exclude 例子
type ExcludePerson = Exclude<PersonKeys, "name">;
const excludePersonKeys: ExcludePerson = "age"; // 只能为age
// T extends U 就判断是否’name’ | ‘age’, 有 name, 有name就返回never,就代表将其排除
type MyExclude<T, U> = T extends U ? never : T;
Extract
源码:
type Extract<T, U> = T extends U ? T : never
作用: 和 Exclude 相反
type A = number | string | boolean
type B = number | boolean
type Foo = Extract<A, B>
// 相当于
type Foo = number | boolean
使用 Extract 例子
Omit【省略: 将接口或者类型的键值对删除一部分】
源码定义:
type Omit<T, K extends string | number | symbol> = {
[P in Exclude<keyof T, K>]: T[P];
};
作用:生成一个新类型,该类型拥有 T 中除了 K 属性以外的所有属性
type Foo = {
name: string
age: number
}
type Bar = Omit<Foo, 'age'>
// 相当于
type Bar = {
name: string
}
使用 Omit 例子
type SomeOfPerson = Omit<Person, 'name'>;
const omitPersonInstance: SomeOfPerson = {
age: 20,
// name: 1, // 不能有name属性 会报错
};
type MyOmit<T, K extends string|number|symbol> = {
[P in Exclude<keyof T, K>]: T[P]
}
NonNullable
源码定义:
NonNullable<T>
作用:从泛型 T 中排除掉 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T;
type t = NonNullable<'name' | undefined | null>;
/* type t = 'name' */
Parameters
源码定义:
Parameters<T extends (...args: any) => any>
作用:以元组的方式获得函数的入参类型
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type t = Parameters<(name: string) => any>; // type t = [string]
type t2 = Parameters<((name: string) => any) | ((age: number) => any)>; // type t2 = [string] | [number]
ConstructorParameters
源码定义:
ConstructorParameters<T extends new (...args: any) => any>
作用:以元组的方式获得构造函数的入参类型
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
type t = ConstructorParameters<(new (name: string) => any) | (new (age: number) => any)>;
// type t = [string] | [number]
ReturnType
源码定义:
ReturnType<T extends (...args: any) => any>
作用:获得函数返回值的类型
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
type t = ReturnType<(name: string) => string | number>
// type t = string | number
InstanceType
源码定义:
InstanceType<T extends new (...args: any) => any>
作用:获得构造函数返回值的类型
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
type t = InstanceType<new (name: string) => {
name: string, age: number}>
/* type h = { name: string; age: number; } */
联合类型 | 交叉类型 &
let a: string | number = "123"; // 变量a的类型既可以是string,也可以是number
a = 123;
// 交叉类型
interface Student {
classNo: string;
}
interface Person {
name: string;
}
const a: Student&Person = {
classNo: "123",
name: "fe"
}
keyof
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // 等同于 type PersonKeys = 'name' | 'age'
const p1: PersonKeys = "name"; // 可以
const p2: PersonKeys = "age"; // 可以
// const p3: PersonKeys = 'height' // 不能将类型“"height"”分配给“name | age”
ts中可以选择一个原来的接口中一部分的属性定义
type PickPerson = Pick<Person, 'name'>;
const pickPersonInstance: PickPerson = {
name: 'FE',
// age: 20, // 不能有age属性, 会报错
};
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface 和 type的区别
一般来说,interface 与 type 区别很小,比如以下两种写法差不多
interface A {
a: number;
b: number;
};
type B = {
a: number;
b: number;
}
其中 interface 同名可以自动合并多个,而 type 只能使用 & 类进行连接
interface A {
a: number;
}
interface A {
b: number;
}
const a: A = {
a: 3,
b: 4
}
其他人写的比较好的文章链接:7.5k字总结typescript
总结:
1、重点理解这些内置的工具类型的定义
2、能够以此为参考写一些工具类型并运用到项目中去