typeScript 泛型
| 1、软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能 |
| |
| 2、在像 C |
| |
| 3、设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是 |
| |
| 1、类的实例成员 |
| |
| 2、类的方法 |
| |
| 3、函数参数 |
| |
| 4、函数返回值 |
| |
| 4、泛型(Generics)是允许同一个函数接受不同类型参数的一种模板 |
| |
| 5、相比于使用 any 类型,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型 |
泛型接口 interface GenericIdentityFn
| interface GenericIdentityFn<T> { |
| (arg: T): T; |
| } |
泛型类
| class GenericNumber<T> { |
| zeroValue: T; |
| add: (x: T, y: T) => T; |
| } |
| |
| let myGenericNumber = new GenericNumber<number>(); |
| myGenericNumber.zeroValue = 0; |
| myGenericNumber.add = function (x, y) { |
| return x + y; |
| }; |
泛型变量
| 1、对刚接触 TypeScript 泛型,看到 T 和 E,还有 K 和 V 这些泛型变量时,估计会一脸懵逼 |
| |
| 2、其实这些大写字母并没有什么本质的区别,只不过是一个约定好的规范而已 |
| |
| 3、也就是说使用大写字母 A-Z 定义的类型变量都属于 泛型,把 T 换成 A,也是一样的 |
| |
| 4、下面介绍一下一些常见泛型变量代表的意思 |
| |
| 1、T(Type):表示一个 TypeScript 类型 |
| |
| 2、K(Key):表示对象中的键类型 |
| |
| 3、V(Value):表示对象中的值类型 |
| |
| 4、E(Element):表示元素类型 |
泛型工具类型
| 1、为了方便开发者 TypeScript 内置了一些常用的工具类型,比如 Partial、Required、Readonly、Record 和 ReturnType 等 |
| |
| 2、要使用 TypeScript 泛型工具类型 需要掌握一些相关的基础知识 |
| |
| 1、typeof |
| |
| 2、keyof |
| |
| 3、in |
| |
| 4、infer |
| |
| 5、extends |
| |
| 3、最后介绍 Partial 工具类型 |
typeof
| 在 TypeScript 中,typeof 操作符可以用来获取一个 变量声明 或 对象 的类型 |
| |
| interface Person { |
| name: string; |
| age: number; |
| } |
| |
| const sem: Person = { name: 'semlinker', age: 30 }; |
| type Sem= typeof sem; |
| |
| function toArray(x: number): Array<number> { |
| return [x]; |
| } |
| |
| type Func = typeof toArray; |
keyof
| keyof 操作符可以用来遍历一个对象中的所有 key 值 |
| |
| interface Person { |
| name: string; |
| age: number; |
| } |
| |
| type K1 = keyof Person; // "name" | "age" |
| type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" |
| type K3 = keyof { [x: string]: Person }; // string | number |
in
| in 用来遍历枚举类型 |
| |
| type Keys = "a" | "b" | "c" |
| |
| type Obj = { |
| [p in Keys]: any |
| } |
infer
| 在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用 |
| |
| type ReturnType<T> = T extends ( |
| ...args: any[] |
| ) => infer R ? R : any; |
| |
| 以上代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用 |
extends
| 有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束 |
| |
| interface ILengthwise { |
| length: number; |
| } |
| |
| function loggingIdentity<T extends ILengthwise>(arg: T): T { |
| console.log(arg.length); |
| return arg; |
| } |
| |
| 现在这个泛型函数被定义了约束,因此它不再是适用于任意类型 |
| |
| loggingIdentity(3); |
| |
| 这时我们需要传入符合约束类型的值,必须包含必须的属性 |
| |
| loggingIdentity({length: 10, value: 3}) |
Partial
| Partial<T> 的作用就是将某个类型里的属性全部变为可选项 ? |
| |
| |
| |
| |
| |
| type Partial<T> = { |
| [P in keyof T]?: T[P]; |
| }; |
| |
| 在以上代码中,首先通过 keyof T 拿到 T 的所有属性名,然后使用 in 进行遍历,将值赋给 P,最后通过 T[P] 取得相应的属性值。中间的 ? 号,用于将所有属性变为可选 |
| |
| 示例 |
| |
| interface Todo { |
| title: string; |
| description: string; |
| } |
| |
| function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) { |
| return { ...todo, ...fieldsToUpdate }; |
| } |
| |
| const todo1 = { |
| title: "organize desk", |
| description: "clear clutter", |
| }; |
| |
| const todo2 = updateTodo(todo1, { |
| description: "throw out trash", |
| }) |
| |
| 在上面的 updateTodo 方法中,我们利用 Partial<T> 工具类型,定义 fieldsToUpdate 的类型为 Partial<Todo>,即 |
| |
| { |
| title?: string | undefined; |
| description?: string | undefined; |
| } |
typeScript 装饰器
装饰器是什么
| 1、它是一个表达式 |
| |
| 2、该表达式被执行后,返回一个函数 |
| |
| 3、函数的入参分别为 target、name 和 descriptor |
| |
| 4、执行该函数后,可能返回 descriptor 对象,用于配置 target 对象 |
装饰器的分类
| 1、类装饰器 【 Class decorators 】 |
| |
| 2、属性装饰器 【 Property decorators 】 |
| |
| 3、方法装饰器 【 Method decorators 】 |
| |
| 4、参数装饰器 【 Parameter decorators 】 |
类装饰器
| 1、类装饰器 声明 |
| |
| declare type ClassDecorator = <TFunction extends Function>( |
| target: TFunction |
| ) => TFunction | void; |
| |
| 2、类装饰器 就是用来装饰类的,它接收一个参数 |
| |
| target: TFunction - 被装饰的类 |
| |
| 3、示例 |
| |
| function Greeter(target: Function): void { |
| target.prototype.greet = function (): void { |
| console.log("Hello Semlinker!"); |
| }; |
| } |
| |
| @Greeter |
| class Greeting { |
| constructor() { |
| |
| } |
| } |
| |
| let myGreeting = new Greeting(); |
| myGreeting.greet(); |
| |
| 上面的例子中,我们定义了 Greeter 类装饰器,同时我们使用了 @Greeter 语法糖,来使用装饰器 |
属性装饰器
| 1、属性装饰器 声明 |
| |
| declare type PropertyDecorator = (target:Object, |
| propertyKey: string | symbol ) => void; |
| |
| 2、属性装饰器用来装饰类的属性,它接收两个参数 |
| |
| 1、target: Object - 被装饰的类 |
| |
| 2、propertyKey: string | symbol - 被装饰类的属性名 |
| |
| 3、示例 |
| |
| function logProperty(target: any, key: string) { |
| delete target[key]; |
| |
| const backingField = "_" + key; |
| |
| Object.defineProperty(target, backingField, { |
| writable: true, |
| enumerable: true, |
| configurable: true |
| }); |
| |
| |
| const getter = function (this: any) { |
| const currVal = this[backingField]; |
| console.log(`Get: ${key} => ${currVal}`); |
| return currVal; |
| }; |
| |
| |
| const setter = function (this: any, newVal: any) { |
| console.log(`Set: ${key} => ${newVal}`); |
| this[backingField] = newVal; |
| }; |
| |
| |
| Object.defineProperty(target, key, { |
| get: getter, |
| set: setter, |
| enumerable: true, |
| configurable: true |
| }); |
| } |
| |
| class Person { |
| @logProperty |
| public name: string; |
| |
| constructor(name : string) { |
| this.name = name; |
| } |
| } |
| |
| const p1 = new Person("semlinker"); |
| p1.name = "kakuqo"; |
| |
| 以上代码定义了一个 logProperty 函数,来跟踪用户对属性的操作,当代码成功运行后,在控制台会输出以下结果 |
| |
| Set: name => semlinker |
| Set: name => kakuqo |
方法装饰器
| 1、方法装饰器 声明 |
| |
| declare type MethodDecorator = <T>(target:Object, propertyKey: string | symbol, |
| descriptor: TypePropertyDescript<T>) => TypedPropertyDescriptor<T> | void; |
| |
| 2、方法装饰器 用来装饰类的方法,它接收三个参数 |
| |
| 1、target: Object - 被装饰的类 |
| |
| 2、propertyKey: string | symbol - 方法名 |
| |
| 3、descriptor: TypePropertyDescript - 属性描述符 |
| |
| 3、示例 |
| |
| function LogOutput(tarage: Function, key: string, descriptor: any) { |
| let originalMethod = descriptor.value; |
| let newMethod = function(...args: any[]): any { |
| let result: any = originalMethod.apply(this, args); |
| if(!this.loggedOutput) { |
| this.loggedOutput = new Array<any>(); |
| } |
| this.loggedOutput.push({ |
| method: key, |
| parameters: args, |
| output: result, |
| timestamp: new Date() |
| }); |
| return result; |
| }; |
| descriptor.value = newMethod; |
| } |
| |
| class Calculator { |
| @LogOutput |
| double (num: number): number { |
| return num * 2; |
| } |
| } |
| |
| let calc = new Calculator(); |
| calc.double(11); |
| |
| console.log(calc.loggedOutput); |
参数装饰器
| 1、参数装饰器 声明 |
| |
| declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, |
| parameterIndex: number ) => void |
| |
| 2、参数装饰器 是用来装饰函数参数,它接收三个参数 |
| |
| 1、target: Object - 被装饰的类 |
| |
| 2、propertyKey: string | symbol - 方法名 |
| |
| 3、parameterIndex: number - 方法中参数的索引值 |
| |
| 4、示例 |
| |
| function Log(target: Function, key: string, parameterIndex: number) { |
| let functionLogged = key || target.prototype.constructor.name; |
| console.log(`The parameter in position ${parameterIndex} at ${functionLogged} has |
| been decorated`); |
| } |
| |
| class Greeter { |
| greeting: string; |
| constructor(@Log phrase: string) { |
| this.greeting = phrase; |
| } |
| } |
| |
| |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!