🔥TS进阶之「类型演算」
类型演算
根据已知的信息,计算出新的类型
三个关键字
typeof
Ts中的typeof
,书写的位置在类型约束的位置上
表示: 获取某个数据的类型
const a: number = 12
// 表示b获取a的类型
let b: typeof a = 22
场景: 通过一个函数的参数传递一个用户类进来创建一个用户对象,函数返回的是一个用户对象
class User{
loginId: string
loginPwd: string
}
function createUser(className: ???): User{
return new className();
}
const u = createUser(User)
第一种约束参数: 使用构造函数进行约束
function createUser(className: new () => User): User{
return new className();
}
第二种约束参数: 使用typeof
,表示计算的类型是这个类的构造函数
当typeof
作用于类的时候,得到的类型,是该类的构造函数
function createUser(className: typeof User): User{
return new className();
}
keyof
作用于类、接口、类型别名,用于获取其他类型中的所有成员名组成的联合类型
场景:使用一个函数,传递一个类对象和属性名,打印出该属性的值
class User{
loginId: string
loginPwd: string
age: number
}
// 打印对象的属性值
function printUserProperty(obj: User, prop: string){
console.log(obj[prop])
}
const u: User = {
loginId: 'sss',
loginPwd: '123456',
age: 18
}
printUserProperty(u, "age")
在以往的写法中,我们在函数传递类的属性名约束为字符串,TS会进行报错,因为后续人为的我们进行修改属性名,TS推断不出一个类里面所有的属性名,导致报错,可以使用之前的联合类型对类中的属性进行约束,比如:
function printUserProperty(obj: User, prop: "loginId" | "loginPwd" | "age"){
console.log(obj[prop])
}
但这样也会存在隐患,后续我们进行修改属性名,函数中也需要进行对应的修改,会带来很多的时间成本。这时,可以使用keyof
进行获取类中的所有的成员组合成联合类型,如下:
function printUserProperty(obj: User, prop: keyof User){
console.log(obj[prop])
}
in
该关键字往往和keyof
联用,用来限制某个索引类型的取值范围。
场景: 将User的所有属性值类型变成字符串,得到一个新类型
interface User{
loginId: string
loginPwd: string
age: number
pid: string
}
// 对索引器的属性名进行约束
type UserString = {
// [p: string]: string
// [p in "loginId" | "loginPwd" | "age"]: string
[p in keyof User]: string
}
const u: UserString = {
loginId: "123",
loginPwd: '123123',
age: '12',
pid: "123123"
}
将属性的名字和类型全部来自用户类:
type UserReadonly = {
[p in keyof User]: User[p]
}
将属性的名字和类型变为只读属性,变成一个新的类型:
type UserReadonly = {
readonly [p in keyof User]: User[p]
}
结合泛型使用:
interface User{
loginId: string
loginPwd: string
age: number
pid: string
}
// 属性的名字和类型全部来自用户类
type UserReadonly<T> = {
[p in keyof T]?: T[p]
}
const u: UserReadonly<User> = {
loginId: "12322",
loginPwd: '123123',
}
TS中预设的类型演算
Partial<T>
将类型T中的成员变为可选
本质:
type Partial<T> = {
[p in keyof T]: T[p]
}
实例:
interface User{
age: number
name: string
}
let u: Partial<User>;
u = {
name: 'huahua'
}
Required<T>
将类型T中的成员变为必填
本质:
type Required<T> = {
[p in keyof T]-?: T[p]
}
实例:
interface User{
age: number
name: string
}
let u: Required<User>;
u = {
name: 'huahua',
age: 12
}
Readonly<T>
将类型T中的成员变为只读
本质:
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
实例:
interface User{
age: number
name: string
}
let u: Readonly<User>;
u = {
name: 'huahua',
age: 12
}
u.age = 18 // 无法为“age”赋值,因为它是只读属性
Exclude<T, U>
将T中剔除可以赋值给U的类型
本质:
type Exclude<T, U> = T extends U ? never : T;
实例:
let u: Exclude< "a"| "b"|"c"|"d", "b"|"c">
// let u: "a" | "d"
type T = "男" | "女" | null | undefined
type NEWT = Exclude<T, null | undefined>
// NEWT = "男" | "女"
Extract<T, U>
提取T中可以赋值给U的类型
本质:
type Extract<T, U> = T extends U ? T : never;
实例:
type T = "男" | "女" | null | undefined
type NEWT = Extract<T, "男" | "女">
// NEWT = "男" | "女"
NonNullable<T>
从T中剔除 null 和 undefined
本质:
type NonNullable<T> = T & {};
实例:
type str = string | null | undefined;
type strNotEmpty = NonNullable<str>
// type strNotEmpty = string
ReturnType<T>
获取函数返回值类型
本质:
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// 关键词infer: 推断出一个类型
实例:
type func = () => number
type returnType = ReturnType<func>
// func返回值类型为number
function sum(a:number, b:number){
return a + b;
}
let a: ReturnType<typeof sum>;
// sum返回值类型为number
InstanceType<T>
获取构造函数类型的实例类型
本质:
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
实例:
class User{
loginId: string
loginPwd: string
}
let u: InstanceType<typeof User>
转载自:https://juejin.cn/post/7272632260179509282