🔥TS进阶之「类型演算」

类型演算

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

三个关键字

typeof

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

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

ts 复制代码
const a: number = 12
// 表示b获取a的类型
let b: typeof a = 22

场景: 通过一个函数的参数传递一个用户类进来创建一个用户对象,函数返回的是一个用户对象

ts 复制代码
class User{
  loginId: string
  loginPwd: string
}

function createUser(className: ???): User{
  return new className();
}

const u = createUser(User)

第一种约束参数: 使用构造函数进行约束

ts 复制代码
function createUser(className: new () => User): User{
  return new className();
}

第二种约束参数: 使用typeof,表示计算的类型是这个类的构造函数

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

ts 复制代码
function createUser(className: typeof User): User{
  return new className();
}

keyof

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

场景:使用一个函数,传递一个类对象和属性名,打印出该属性的值

ts 复制代码
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推断不出一个类里面所有的属性名,导致报错,可以使用之前的联合类型对类中的属性进行约束,比如:

ts 复制代码
function printUserProperty(obj: User, prop: "loginId" | "loginPwd" | "age"){
  console.log(obj[prop])
}

但这样也会存在隐患,后续我们进行修改属性名,函数中也需要进行对应的修改,会带来很多的时间成本。这时,可以使用keyof进行获取类中的所有的成员组合成联合类型,如下:

ts 复制代码
function printUserProperty(obj: User, prop: keyof User){
  console.log(obj[prop])
}

in

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

场景: 将User的所有属性值类型变成字符串,得到一个新类型

ts 复制代码
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"
}

将属性的名字和类型全部来自用户类:

ts 复制代码
type UserReadonly = {
  [p in keyof User]: User[p]
}

将属性的名字和类型变为只读属性,变成一个新的类型:

ts 复制代码
type UserReadonly = {
  readonly [p in keyof User]: User[p]
}

结合泛型使用:

ts 复制代码
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中的成员变为可选

本质:

ts 复制代码
type Partial<T> = {
    [p in keyof T]: T[p]
}

实例:

ts 复制代码
interface User{
  age: number
  name: string
}
let u: Partial<User>;
u = {
  name: 'huahua'
}

Required<T> 将类型T中的成员变为必填

本质:

ts 复制代码
type Required<T> = {
    [p in keyof T]-?: T[p]
}

实例:

ts 复制代码
interface User{
  age: number
  name: string
}
let u: Required<User>;
u = {
  name: 'huahua',
  age: 12
}

Readonly<T> 将类型T中的成员变为只读

本质:

ts 复制代码
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

实例:

ts 复制代码
interface User{
  age: number
  name: string
}

let u: Readonly<User>;
u = {
  name: 'huahua',
  age: 12
}
u.age = 18 // 无法为"age"赋值,因为它是只读属性

Exclude<T, U> 将T中剔除可以赋值给U的类型

本质:

ts 复制代码
type Exclude<T, U> = T extends U ? never : T;

实例:

ts 复制代码
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的类型

本质:

ts 复制代码
type Extract<T, U> = T extends U ? T : never;

实例:

ts 复制代码
type T = "男" | "女" | null | undefined
type NEWT = Extract<T, "男" | "女">
// NEWT = "男" | "女"

NonNullable<T> 从T中剔除 null 和 undefined

本质:

ts 复制代码
type NonNullable<T> = T & {};

实例:

ts 复制代码
type str = string | null | undefined;
type strNotEmpty = NonNullable<str>
// type strNotEmpty = string

ReturnType<T> 获取函数返回值类型

本质:

ts 复制代码
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

// 关键词infer: 推断出一个类型

实例:

ts 复制代码
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> 获取构造函数类型的实例类型

本质:

ts 复制代码
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;

实例:

ts 复制代码
class User{
  loginId: string
  loginPwd: string
}

let u: InstanceType<typeof User>
相关推荐
BillKu16 小时前
Vue3 + TypeScript + Element Plus 表格行按钮不触发 row-click 事件、不触发勾选行,只执行按钮的 click 事件
vue.js·elementui·typescript
霸王蟹19 小时前
前端项目Excel数据导出同时出现中英文表头错乱情况解决方案。
笔记·学习·typescript·excel·vue3·react·vite
半醉看夕阳1 天前
HarmonyOS开发 ArkTS 之 var 、let、const 变量声明的剖析
typescript·harmonyos·arkts
BillKu1 天前
Vue3 + TypeScript 操作第三方库(Element Plus 的 ElTable)的内部属性
前端·javascript·typescript
好了来看下一题1 天前
TypeScript 项目配置
前端·javascript·typescript
霸王蟹1 天前
带你手写React中的useReducer函数。(底层实现)
前端·javascript·笔记·学习·react.js·typescript·前端框架
码农之王1 天前
(二)TypeScript前置编译配置
前端·后端·typescript
Raink老师1 天前
7. TypeScript接口
javascript·typescript
涵信2 天前
第一节 基础核心概念-TypeScript与JavaScript的核心区别
前端·javascript·typescript
涵信2 天前
第九节 高频代码题-实现Sleep函数(异步控制)
前端·javascript·typescript