likes
comments
collection
share

🔥TS进阶之「类型演算」

作者站长头像
站长
· 阅读数 61

类型演算

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

三个关键字

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
评论
请登录