欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > TS泛型笔记

TS泛型笔记

2025/8/11 0:50:18 来源:https://blog.csdn.net/2403_87169202/article/details/148885610  浏览:    关键词:TS泛型笔记
1. 泛型基础概念

定义:泛型是 TypeScript 中允许创建可复用组件的特性,这些组件可以支持多种数据类型,而非单一特定类型。

核心优势

  • 代码复用性:同一组件可处理不同类型数据
  • 类型安全:在编译阶段捕获类型错误
  • 灵活性:保持代码的灵活性同时提供强类型支持

泛型函数

// 基础泛型函数语法
function identity<T>(arg: T): T {return arg;
}// 使用方式
const result = identity<string>("hello"); // 指定类型参数
const inferredResult = identity(123); // 类型自动推断为 number

泛型类

class Box<T> {private value: T;constructor(value: T) {this.value = value;}getValue(): T {return this.value;}
}// 使用示例
const numberBox = new Box<number>(42);
const stringBox = new Box("text"); // 类型自动推断
2. 泛型约束详解

基本约束

interface HasLength {length: number;
}// 约束 T 必须实现 HasLength 接口
function getLength<T extends HasLength>(arg: T): number {return arg.length;
}// 有效调用
getLength("hello"); // 字符串有 length 属性
getLength([1, 2, 3]); // 数组有 length 属性// 错误调用
getLength(123); // 数字没有 length 属性

键约束

// 约束 K 必须是 T 类型的键
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {return obj[key];
}const user = { name: "Alice", age: 30 };
const name = getProperty(user, "name"); // 正确
const invalid = getProperty(user, "address"); // 错误:address 不是 user 的键

构造函数约束

interface Constructor<T> {new (...args: any[]): T;
}function createInstance<T>(ctor: Constructor<T>): T {return new ctor();
}class MyClass {constructor() {}
}const instance = createInstance(MyClass); // 创建 MyClass 实例
3. 接口深入理解

接口定义

interface Person {name: string;age?: number; // 可选属性readonly id: number; // 只读属性[propName: string]: any; // 任意属性
}// 使用接口
const person: Person = {name: "Bob",id: 12345,address: "123 Street" // 任意属性
};person.age = 30; // 可选属性可赋值
person.id = 67890; // 错误:只读属性不可修改

接口继承

interface Shape {color: string;
}interface Square extends Shape {sideLength: number;
}// 实现接口
const square: Square = {color: "blue",sideLength: 10
};

函数类型接口

interface SearchFunc {(source: string, subString: string): boolean;
}const mySearch: SearchFunc = function(src, sub) {return src.includes(sub);
};
4. 泛型与接口结合应用

泛型接口

interface Container<T> {value: T;getValue: () => T;setValue: (newValue: T) => void;
}// 实现泛型接口
class BoxContainer<T> implements Container<T> {constructor(private _value: T) {}getValue() {return this._value;}setValue(newValue: T) {this._value = newValue;}
}

泛型工具类型

// Partial<T> - 创建所有属性可选的类型
interface User {name: string;age: number;
}type PartialUser = Partial<User>; 
// 等价于 { name?: string; age?: number; }// Readonly<T> - 创建所有属性只读的类型
type ReadonlyUser = Readonly<User>;// Pick<T, K> - 从 T 中选择一组属性 K
type NameOnly = Pick<User, "name">; 
// 等价于 { name: string; }// Record<K, T> - 创建一个 K 类型为键,T 类型为值的对象类型
type UserRecords = Record<string, User>;
5. 高级泛型技术

条件类型

// 基本条件类型语法
type IsString<T> = T extends string ? true : false;type A = IsString<string>; // true
type B = IsString<number>; // false// 分布式条件类型
type ToArray<T> = T extends any ? T[] : never;type StringArray = ToArray<string>; // string[]
type NumberOrStringArray = ToArray<number | string>; // number[] | string[]

映射类型

// 基本映射类型
type Readonly<T> = {readonly [P in keyof T]: T[P];
};type Optional<T> = {[P in keyof T]?: T[P];
};// 使用示例
type ReadonlyUser = Readonly<User>;
type OptionalUser = Optional<User>;

类型推断与 infer

// 提取函数返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;type Num = ReturnType<() => number>; // number
type Str = ReturnType<(s: string) => string>; // string

案例 1:实现一个通用的响应接口

interface ApiResponse<T> {code: number;message: string;data: T;
}// 使用示例
type UserResponse = ApiResponse<User>;
type ProductListResponse = ApiResponse<Product[]>;// 处理 API 响应
function processResponse<T>(response: ApiResponse<T>): T {if (response.code === 200) {return response.data;}throw new Error(response.message);
}

案例 2:实现一个泛型缓存类

class Cache<T> {private storage: Map<string, T> = new Map();set(key: string, value: T): void {this.storage.set(key, value);}get(key: string): T | undefined {return this.storage.get(key);}clear(): void {this.storage.clear();}
}// 使用示例
const userCache = new Cache<User>();
userCache.set("currentUser", { name: "Alice", age: 30 });
const currentUser = userCache.get("currentUser");

案例总结

  1. 明确类型参数:除非类型可以被可靠推断,否则明确指定泛型类型参数
  2. 约束类型参数:使用泛型约束确保类型参数满足特定条件
  3. 避免过度泛型:仅在必要时使用泛型,避免增加不必要的复杂性
  4. 优先使用接口而非类型别名:对于对象类型定义,优先使用 interface 而非 type
  5. 使用工具类型:利用 TypeScript 内置的工具类型(Partial、Readonly 等)简化常见操作
常见错误与解决方案

错误 1:泛型函数返回类型不匹配

// 错误示例
function createArray<T>(length: number, value: T): number[] {return Array(length).fill(value); // 错误:可能返回非 number[] 类型
}// 解决方案
function createArray<T>(length: number, value: T): T[] {return Array(length).fill(value);
}

错误 2:接口属性冲突

// 错误示例
interface A { x: number; }
interface B { x: string; }
interface C extends A, B {} // 错误:属性 x 类型冲突// 解决方案
interface C { x: number | string; } // 联合类型解决冲突

错误 3:泛型约束不足

// 错误示例
function getLength<T>(arg: T): number {return arg.length; // 错误:T 不一定有 length 属性
}// 解决方案
function getLength<T extends { length: number }>(arg: T): number {return arg.length;
}
与其他 TypeScript 特性的组合

泛型与装饰器

function logClass<T extends { new (...args: any[]): {} }>(constructor: T) {return class extends constructor {constructor(...args: any[]) {console.log("Creating instance with arguments:", args);super(...args);}};
}@logClass
class MyClass {constructor(public name: string) {}
}const instance = new MyClass("Test"); // 输出: Creating instance with arguments: ["Test"]

泛型与命名空间

namespace Utils {export function identity<T>(arg: T): T {return arg;}
}const result = Utils.identity("hello"); // 使用命名空间中的泛型函数

总结

泛型和接口是 TypeScript 中最强大的两个特性,它们共同构成了 TypeScript 类型系统的核心。通过泛型,我们可以创建高度可复用的组件,同时保持类型安全;通过接口,我们可以定义清晰的契约,规范代码结构。合理运用这两个特性,可以显著提升代码质量、可维护性和开发效率。

在实际开发中,建议遵循最佳实践,从简单的泛型应用开始,逐步深入到高级技术。同时,注意避免常见错误,充分利用 TypeScript 提供的工具类型和内置功能,打造健壮、灵活的 TypeScript 应用。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词