Typescript泛型

泛型是什么?

         TypeScript Generics是提供创建可重用组件的方法的工具。 它能够创建可以使用多种数据类型而不是单一数据类型的组件。 而且,它在不影响性能或生产率的情况下提供了类型安全性。 泛型允许我们创建泛型类,泛型函数,泛型方法和泛型接口。

        泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

        在泛型中,类型参数写在左括号(<)和右括号(>)之间,这使它成为强类型集合。 它使用一种特殊的类型变量<T>来表示类型。
 

function createArray(length: number, value: any): Array<any> {
    let result = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']

上例中,我们使用了之前提到过的数组泛型来定义返回值的类型。
这段代码编译不会报错,但是一个显而易见的缺陷是,它并没有准确的定义返回值的类型:
Array 允许数组的每一项都为任意类型。但是我们预期的是,数组中每一项都应该是输入的 value 的类型。
这时候,泛型就派上用场了:

function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray<string>(3, 'x'); // ['x', 'x', 'x']

上例中,我们在函数名后添加了 ,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array 中即可使用了。

接着在调用的时候,可以指定它具体的类型为 string。当然,也可以不手动指定,而让类型推论自动推算出来:

function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']

定义泛型的时候,可以一次定义多个类型参数:

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

swap([7, 'seven']); // ['seven', 7]

上例中,我们定义了一个 swap 函数,用来交换输入的元组。

泛型约束

在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length);
    return arg;
}

// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.

上例中,因为泛型 T 不一定包含属性 length,所以编译的时候报错了,是一个错误的例子。

这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

多个类型参数之间也可以互相约束:

function copyFields<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = (<T>source)[id];
    }
    return target;
}

let x = { a: 1, b: 2, c: 3, d: 4 };

copyFields(x, { b: 10, d: 20 });

泛型接口

使用接口的方式来定义一个函数需要符合的形状:

interface SearchFunc {
  (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
    return source.search(subString) !== -1;
}

当然也可以使用含有泛型的接口来定义函数的形状:

interface CreateArrayFunc {
    <T>(length: number, value: T): Array<T>;
}

let createArray: CreateArrayFunc;
createArray = function<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']
interface CreateArrayFunc<T> {
    (length: number, value: T): Array<T>;
}

let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

createArray(3, 'x'); // ['x', 'x', 'x']

使用泛型接口的时候,需要定义泛型的类型。

泛型类

与泛型接口类似,泛型也可以用于类的类型定义中:

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; };

泛型参数的默认类型

在 TypeScript 2.3 以后,我们可以为泛型中的类型参数指定默认类型。当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用。

function createArray<T = string>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}

<think>我们根据用户需求,结合站内引用资料,系统整理TypeScript的相关信息。 注意:由于引用标记在用户输入中已明确(如[^1]),我们在回答中直接使用这些引用标记。 用户需求:了解TypeScript的介绍、使用方法及相关知识。 回答结构: 1. 简介(定义、目的) 2. 为什么需要(解决的问题) 3. 的使用方法(函数、接口、类) 4. 约束(限制的类范围) 5. 参数默认类 6. 常见应用场景 注意:使用中文回答,按照系统指令要求正确使用行内公式(虽然这个主题可能较少涉及数学公式,但如果有表达式如类参数等,可以用$...$表示)和独立公式(如果有的话)。 但根据内容,可能较少涉及数学公式,因此主要关注代码示例和文字描述。 同时,在回答末尾生成相关问题。 </think>### TypeScript详解 #### 一、介绍 (Generics)是TypeScript的核心特性,允许在定义函数、接口或类时不预先指定具体类,而是在使用时动态指定类。这种**参数化类**机制通过`<T>`语法实现,其中`T`是类变量(可自定义名称)。的主要价值在于: 1. **代码复用**:编写可适用于多种类的通用组件[^3] 2. **类安全**:编译器在编译阶段进行类检查,避免运行时错误[^3] 3. **灵活性**:保持类约束的同时支持不同类操作[^4] #### 二、基本使用方法 ##### 1. 函数 ```typescript function identity<T>(arg: T): T { return arg; } // 显式指定类 let output1 = identity<string>("Hello"); // string类 // 类推断 let output2 = identity(42); // number类(自动推断) ``` ##### 2. 接口 ```typescript interface KeyValuePair<K, V> { key: K; value: V; } // 使用 const pair: KeyValuePair<number, string> = { key: 1, value: "Apple" }; ``` ##### 3. 类 ```typescript class GenericQueue<T> { private data: T[] = []; push(item: T) { this.data.push(item); } pop(): T | undefined { return this.data.shift(); } } // 使用 const stringQueue = new GenericQueue<string>(); stringQueue.push("A"); stringQueue.push("B"); ``` #### 三、高级特性 1. **约束**:限制类参数的范围 ```typescript interface Lengthwise { length: number; } function logLength<T extends Lengthwise>(arg: T): void { console.log(arg.length); } logLength("text"); // 4 logLength([1, 2, 3]); // 3 ``` 2. **默认类参数** ```typescript function createArray<T = string>(length: number, value: T): T[] { return Array(length).fill(value); } createArray(3, "x"); // string[] createArray<number>(3, 5); // number[] ``` 3. **多类参数** ```typescript function swap<T, U>(tuple: [T, U]): [U, T] { return [tuple[1], tuple[0]]; } swap([7, "seven"]); // 返回 ["seven", 7] ``` #### 四、应用场景 1. **集合操作**:数组、栈、队列等数据结构的通用实现 2. **API响应处理**:统一处理不同类API返回的数据结构 3. **工具函数**:如`map`/`filter`等可复用高阶函数 4. **状态管理**:Redux的Action/Reducer类定义 5. **React组件**:通用组件Props的类约束 #### 五、最佳实践 1. 优先使用单字母类参数(`T`/`U`/`K`/`V`) 2. 当类关系复杂时,使用`extends`添加约束 3. 避免过度化,保持类可读性 4. 利用类推断减少显式类声明 > 通过TypeScript在保持JavaScript灵活性的同时,提供了强类语言的可靠性和工具支持,大幅提升大项目的可维护性[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值