🔥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>
相关推荐
百万蹄蹄向前冲3 小时前
让TypeScript 再次伟大:愚人节前夜Claude Code意外开源与OpenClaw小龙虾打造 AI 原生开发新纪元
人工智能·typescript·node.js
wendycwb3 小时前
前端城市地址根据最后一级倒推,获取各层级id的方法
前端·vue.js·typescript
向上的车轮10 小时前
熟悉C#如何转TypeScript——SDK与包引用
开发语言·typescript·c#
紫_龙11 小时前
最新版vue3+TypeScript开发入门到实战教程之Pinia详解
前端·javascript·typescript
吴声子夜歌14 小时前
TypeScript——webpack
javascript·webpack·typescript
LXXgalaxy17 小时前
Vue3 + TypeScript 20 个常见报错
javascript·ubuntu·typescript
海兰17 小时前
使用 TypeScript 创建 Elasticsearch MCP 服务器
服务器·elasticsearch·typescript·mcp
We་ct17 小时前
LeetCode 373. 查找和最小的 K 对数字:题解+代码详解
前端·算法·leetcode·typescript·二分·
吴声子夜歌1 天前
TypeScript——基础类型(三)
java·linux·typescript
guangzan1 天前
Pretext:值得关注的文本排版引擎
typescript