Skip to content
在本页面

类型演算 🎶

根据已知的信息,计算出新的类型

typeof 关键字

TS中的typeof,书写的位置在类型约束的位置上。

表示:获取某个数据的类型

WARNING

TS中的typeof,与JS中的typeof不太一样,根据作用的位置区分

ts
const a: string = 'abc'

let b: typeof a = 'dasdas'
// 让b与a的类型保持一致

typeof作用于类的时候,得到的类型,是该类的构造函数

ts
class User {
    loginId: string
    loginPwd: string
}
// typeof User 计算出来的是User的构造函数,直接书写User表示的是类本身
function createUser(cls: typeof User): User {
    return new cls();
}
// 需要传递一个 构造函数 生成一个用户对象
const u = createUser(User);

keyof 关键字

作用于类、接口、类型别名,用于获取其他类型中的所有成员名组成的联合类型

ts
interface User {
    loginId: string
    loginPwd: string
    age: number
}
// prop的类型应该是User里某个字段中的一个
// 为什么要用 keyof User:将User类型里的所有成员名拿出来形成的联合类型,是动态的
// 如果你使用联合类型,如果User的属性名更改了,或者后续又增加或修改会导致这里引用prop出问题
function printUserProperty(obj: User, prop: keyof User) {
    console.log(obj[prop]);
}

const u: User = {
    loginId: 'Matt',
    loginPwd: '123145',
    age: 12,
}

printUserProperty(u, "age")

in 关键字

该关键字往往和keyof联用,限制某个索引类型的取值范围

例:有一个如下的User类型

ts
interface User {
    loginId: string
    age: number
    createDate: Date
}

如果你要通过User的所有属性来得到一个全新的,但是类型全部是string的类型可以使用in关键字

ts
type UserString = {
    [p in "loginId" | "age" | "createDate"]: string
}

// 等同于 ⬇️
type UserString = {
    loginId: string
    age: string
    createDate: string
}

const u: UserString = {
    loginId: 'dandv',
    age: '123456',
    createDate: '2022-01-01'
}

但是这样做也不太好,如果后续对原User类型新增、修改或删除属性,你也不能通过F2一次性修改,会造成一些错误

于是可以利用keyof关键字,获取User类型里的所有类型

ts
type UserString = {
    [p in keyof User]: string
}

// 等同于 ⬇️
type UserString = {
    loginId: string
    age: string
    createDate: string
}

也可以:新类型和原User类型的类型也保持一致

ts
type newUser = {
    [p in keyof User]: User[p]
}

// 等同于 ⬇️
type newUser = {
    loginId: string
    age: number
    createDate: Date
}

也可以:属性全部只读

ts
type UserReadonly = {
    readonly [p in keyof User]: User[p]
}

// 等同于 ⬇️
type UserReadonly = {
    readonly loginId: string
    readonly age: number
    readonly createDate: Date
}

也可以:属性全部可选

ts
type UserPartial = {
    [p in keyof User]?: User[p]
}

// 等同于 ⬇️
type UserPartial = {
    loginId?: string
    age?: number
    createDate?: Date
}

也可以:属性全部可选 类型自定义

ts
type MyPartial<T> = {
    [p in keyof T]?: T[p]
}

也可以:属性全部可选 类型自定义 属性全部只读

ts
type MyReadonly<T> = {
    readonly [p in keyof T]?: T[p]
}

TS中的预设的类型演算

类型演算含义
Partial<T>将类型T中的成员变为可选
Required<T>将类型T中的成员变为必填
Readonly<T>将类型T中的成员变为只读
Exclude<T, U>从T中剔除可以赋值给U的类型
Extract<T, U>提取T中可以赋值给U的类型
NonNullable<T>从T中剔除null和undefined
ReturnType<T>获取函数返回值类型
InstanceType<T>获取构造函数类型的实例类型

TIP

-?标识符:去掉可选

inter关键字:推断

ts
interface User {
    name: string
    age: number
}

let u1: Partial<User> = {
    name: 'dadq',
}

let u2: Required<User> = {
    name: 'dadq',
    age: 0
}

let u3: Readonly<User> = {
    name: 'dadq',
    age: 0
}
ts
type T = "" | "" | null | undefined

// 此时 NEWT 的类型为 "男" | "女" 的联合类型
let NEWT: Exclude<T, null | undefined> = ""
ts
type T = "" | "" | null | undefined

// 此时 NEWT 的类型为 "男" | "女" 的联合类型
let NEWT: Extract<T, "" | "" | "a"> = ""
ts
type str = string | null | undefined

// 此时 strNotEmpty 的类型为 string
type strNotEmpty = NonNullable<str>
ts
// 情况1
type func = () => number

// 得到返回值为 number类型
type returnType = ReturnType<func>

// 情况2
function sum(a:number, b:number) {
    return a + b;
}
// 此时a的类型为 number类型
let a: ReturnType<typeof sum>

如下场景:有一个类型twoParamsConstructor来约束构造函数

ts
class User{
    loginId: string
}
// 约束一个构造函数:必须满足这个条件:构造函数两个参数(鸭子辨型法:参数可以少),返回User
type twoParamsConstructor = new (arg1: any, arg2: any) => User

let A: twoParamsConstructor = class Test extends User {
    constructor(a:any, b:any){
        super()
    }
}

// 此时 Inst 类型为 User
type Inst = InstanceType<twoParamsConstructor>