杂记--关于ts中的泛型

132 阅读2分钟

泛型(Generics)在TypeScript中是一种强大的工具,允许你在定义函数、接口、类等时,不具体指定某个类型,而是在使用的时候指定。这样可以提高代码的复用性和类型安全性。

1. 泛型函数

一个最常见的泛型使用场景是泛型函数。泛型函数允许在函数内部使用未知的类型,并在调用函数时指定这个类型。

// 定义一个泛型函数,T 是类型参数
function identity<T>(arg: T): T {
    return arg;
}

// 调用泛型函数,指定类型为 number
const number = identity<number>(123);
console.log(number); // 输出: 123

// 调用泛型函数,指定类型为 string
const text = identity<string>("Hello, World!");
console.log(text); // 输出: Hello, World!

2. 泛型接口

泛型接口允许在接口内部使用未知的类型,这样实现的类可以指定这个类型。

// 定义一个泛型接口
interface GenericIdentityFn<T> {
    (arg: T): T;
}

// 实现泛型接口,指定类型为 number
const numberIdentity: GenericIdentityFn<number> = (n) => n;
console.log(numberIdentity(42)); // 输出: 42

// 实现泛型接口,指定类型为 string
const stringIdentity: GenericIdentityFn<string> = (s) => s;
console.log(stringIdentity("Hello, World!")); // 输出: Hello, World!

3. 泛型类

泛型类允许你在类定义中使用未知的类型,这样实例化的对象可以指定这个类型。

// 定义一个泛型类
class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;

    constructor(zeroValue: T, add: (x: T, y: T) => T) {
        this.zeroValue = zeroValue;
        this.add = add;
    }
}

// 使用泛型类,指定类型为 number
const myGenericNumber = new GenericNumber<number>(0, (x, y) => x + y);
console.log(myGenericNumber.zeroValue); // 输出: 0
console.log(myGenericNumber.add(1, 2)); // 输出: 3

// 使用泛型类,指定类型为 string
const myGenericString = new GenericNumber<string>("", (x, y) => x + y);
console.log(myGenericString.zeroValue); // 输出: ""
console.log(myGenericString.add("Hello, ", "World!")); // 输出: Hello, World!

4. 泛型约束

有时你可能需要对泛型进行约束,使其必须满足某些条件。你可以使用 extends 关键字来约束泛型类型。

// 定义一个接口
interface Lengthwise {
    length: number;
}

// 定义一个泛型函数,并使用泛型约束
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

// 调用泛型函数,传入一个对象,该对象必须有一个 length 属性
const obj = { length: 10, value: "Hello, World!" };
console.log(loggingIdentity(obj)); // 输出: 10,并返回 { length: 10, value: "Hello, World!" }

// 如果传入的对象没有 length 属性,则会报错
// const objWithoutLength = { value: "Hello, World!" };
// console.log(loggingIdentity(objWithoutLength)); // 错误: 对象字面量可能无法正确赋值给类型 'T'。

5. 多个类型参数

泛型不仅可以有一个类型参数,还可以有多个类型参数。

// 定义一个泛型函数,使用两个类型参数
function pair<T, U>(first: T, second: U): [T, U] {
    return [first, second];
}

// 调用泛型函数,指定类型为 number 和 string
const result = pair<number, string>(1, "one");
console.log(result); // 输出: [1, "one"]

这些示例展示了泛型在TypeScript中的多种用途,从简单的泛型函数到复杂的泛型类,再到带有约束的泛型。