简单了解一下 TypeScript 的泛型

news/2024/11/8 7:36:06 标签: typescript, 泛型, T

TypeScript (TS) 中,泛型是一个强大且灵活的工具,用于编写具有更高可复用性和类型安全性的代码。泛型允许我们在声明时将类型作为参数传入,使函数、接口和类能在不同的数据类型下复用,而无需重新编写逻辑。

1. 泛型的基本语法

泛型的基本语法是在函数、接口、类等结构后添加尖括号 <>,并指定一个类型参数(通常用大写字母如 T 表示)。

🌰:

TypeScript">function identity<T>(arg: T): T {
  return arg;
}

这里 T泛型类型,它表示一个占位符,可以是任何类型。函数 identity 接受一个参数 arg,其类型是 T,并返回相同类型的 T。当我们调用时,可以指定具体类型,如: identity<string>("Hello")。

2. 泛型在函数中的使用

在函数中,泛型可以用来定义参数返回值的类型,从而提高代码的灵活性和可复用性。

一个经典的 🌰 是数组的泛型方法:

TypeScript">function logArray<T>(arr: T[]): T[] {
  console.log(arr);
  return arr;
}

logArray 接收一个类型为 T 数组的参数,并返回该数组,T 可以是任意类型。通过这种方式,我们可以传入 string[]、number[] 等不同类型的数组,而不需要为每种类型写单独的函数。

3. 泛型在接口中的应用

泛型在接口中使用时,可以使接口支持不同的类型数据。

🌰,在定义一个具有 value 属性和 getValue 方法的接口时,可以使用泛型来灵活指定 value 的类型:

TypeScript">interface Box<T> {
  value: T;
  getValue(): T;
}
const stringBox: Box<string> = {
  value: 'Hello',
  getValue() {
    return this.value;
  },
};
const numberBox: Box<number> = {
  value: 18,
  getValue() {
    return this.value;
  },
};

Box<T> 接口可以适用于任何类型的 value,如 string、number,甚至是自定义类型。

4. 泛型在类中的应用

泛型在类中也有广泛的应用,特别是在需要处理不同类型的集合、数据结构时。

🌰:

TypeScript">class Stack<T> {
  private items: T[] = [];
  push(item: T) {
    this.items.push(item);
  }
  pop(): T | undefined {
    return this.items.pop();
  }
}

Stack 类使用了泛型 T,从而可以创建不同类型的栈,如 Stack<number> 或 Stack<string>。

5. 泛型约束(Constraints)

在某些情况下,我们可能希望限制泛型参数的类型范围,可以通过泛型约束实现这一点。

🌰,使用 extends 关键字来约束泛型类型必须具有某些属性或实现某个接口:

TypeScript">interface LengthType {
  length: number;
}
function logLength<T extends LengthType>(arg: T): T {
  console.log(arg.length);
  return arg;
}

logLength 函数的泛型参数 T 被约束为具有 length 属性的类型,这意味着只能传入具有 length 属性的对象,例如数组或字符串。

6. 多个泛型参数

有时一个泛型类型参数无法满足需求,此时可以使用多个泛型参数。

🌰:

TypeScript">function pair<T, U>(a: T, b: U): [T, U] {
  return [a, b];
}
pair(1, 1);
pair(1, '1');
pair('1', true);

pair 函数中,T 和 U 是两个泛型参数,允许我们将任意类型的两个值组合成一个元组。

7. 泛型的默认类型

TypeScript 支持为泛型提供默认类型,这样在没有指定类型时可以使用默认值:

🌰:

TypeScript">function createArray<T = number>(length: number, value: T): T[] {
  return Array(length).fill(value);
}

const arr = createArray(3, 5); // 推断 T 为 number
const strArr = createArray<string>(3, 'Hello'); // 显式指定 T 为 string

createArray 函数中,设置 T 默认类型 number,这样如果调用时不指定类型,T 将默认为 number。

8. 泛型工具类型(Utility Types)

TypeScript 提供了一些内置的工具类型,可以用于处理泛型类型。例如:

- Partial<T>:将类型 T 中的所有属性变成可选。

- Readonly<T>:将类型 T 中的所有属性变为只读。常用于防止对象被修改的情况。

TypeScript">interface User {
  id: number;
  name: string;
  age: number;
}
type PartialUser = Partial<User>; // { id?: number; name?: string; age?: number; }
const user1: PartialUser = { name: 'Alice' }; // 只需要部分属性
const user2: PartialUser = {}; //也可以一个都不写
const user3: Readonly<User> = { id: 1, name: 'Alice', age: 30 }; // { readonly id: number; readonly name: string; readonly age: number; }
// user3.age = 31; // 错误:因为 user 是只读的
// const user4: Readonly<User>; // 'const' declarations must be initialized. 必须初始化 const 声明。

- Record<K, T>:将键类型为 K 的所有键映射到类型 T 的值。K 必须是字符串或字符串字面量的联合类型。常用于创建对象映射或字典。

TypeScript">type Role = 'admin' | 'user' | 'guest';
type Permission = Record<Role, boolean>; // 表示每个角色是否具有某种权限。

const permissions: Permission = {
  admin: true,
  user: false,
  guest: false,
};

- Pick<T, K>:从类型 T 中选择一些属性构成新的类型。

- Omit<T, K>:从类型 T 中剔除一些属性构成新的类型。

TypeScript">interface User {
  id: number;
  name: string;
  age: number;
}
type UserPreview = Pick<User, 'id' | 'name'>;
const userPreview: UserPreview = { id: 1, name: 'Alice' }; // 只包含 id 和 name

type UserWithoutAge = Omit<User, "age">;
const userWithoutAge: UserWithoutAge = { id: 1, name: "Alice" }; // age 属性被去除

9. 泛型的优势与趋势

1、可复用性:泛型允许编写更通用的代码,减少重复,提高可维护性。

2、类型安全:相比于 any,泛型提供了明确的类型约束,能够在编译时捕获错误,提升代码的可靠性。

3、适用性广:泛型在函数、接口、类、工具类型中均可使用。


http://www.niftyadmin.cn/n/5743518.html

相关文章

论文《基于柔顺控制的智能神经导航手术机器人系统设计》文献阅读分析报告

论文报告&#xff1a;基于卷积神经网络的手术机器人控制系统设计 摘要 本研究针对机器人辅助微创手术中定向障碍和缺乏导航信息的问题&#xff0c;设计了一种智能控制导航手术机器人系统。该系统采用可靠和安全的定位技术、7自由度机械臂以及避免关节角度限制的逆运动学控制策…

Android CCodec Codec2 (二十)C2Buffer与Codec2Buffer

在阅读Codec2框架代码时&#xff0c;我们可能会发现好几个名称中都带有“buffer”的类&#xff0c;如MediaCodecBuffer、ABuffer、CCodecBuffers、Codec2Buffer以及C2Buffer。它们分别是什么&#xff1f;各自承担着什么功能&#xff1f;它们之间有何联系&#xff1f;本文将围绕…

macos中安装和设置ninja

1、在安装ninja的过程中需要先安装re2c(github地址&#xff1a;https://github.com/skvadrik/re2c): git clone https://github.com/skvadrik/re2c.git&#xff08;也可直接下载最新的release压缩包&#xff0c;并解压。下载地址&#xff1a;https://github.com/skvadrik/re2c…

[论文阅读]Secure IP Address Allocation at Cloud Scale

Secure IP Address Allocation at Cloud Scale http://arxiv.org/abs/2210.14999 NDSS - Network and Distributed Systems Security Symposium (2025) 随着云计算和云基础设施的广泛应用&#xff0c;云服务提供商必须管理大量的网络资源&#xff0c;其中IP地址分配是重要的…

【Linux】Linux下查看cpu信息指令(top/mpstat/iostat/pidstat)说明

top命令 top(1) - Linux manual page (man7.org) top查看总的CPU利用率 us: 用户空间消耗的CPU资源占比&#xff0c;进程在用户态执行函数调用&#xff0c;编解码消耗的都是us sy: 内核空间消耗的CPU资源占比&#xff0c;进程调用系统调用达到内核后会增加sy的消耗 ni&…

浅谈语言模型推理框架 vLLM 0.6.0性能优化

在此前的大模型技术实践中&#xff0c;我们介绍了加速并行框架Accelerate、DeepSpeed及Megatron-LM。得益于这些框架的助力&#xff0c;大模型的分布式训练得以化繁为简。 然而&#xff0c;企业又该如何将训练完成的模型实际应用部署&#xff0c;持续优化服务吞吐性能&#xf…

salesforce case可以新建一个roll up 字段,统计出这个case下的email数量吗

在 Salesforce 中&#xff0c;标准的 Roll-Up Summary 字段仅支持在主对象和子对象之间的聚合统计&#xff0c;而邮件&#xff08;Email Message&#xff09;通常与 Case 是通过活动&#xff08;Activity&#xff09;或任务&#xff08;Task&#xff09;间接关联的&#xff0c;…

【Ubuntu20】VSCode Python代码规范工具配置 Pylint + Black + MyPy + isort

​ 常用工具&#xff1a; 在 Ubuntu20 下&#xff0c;有以下常见的 Python 代码工具&#xff1a; 静态分析工具&#xff1a; Pylint 和 Flake8 功能范围&#xff1a;Pylint功能非常强大&#xff0c;能够检查代码质量、潜在错误、代码风格、复杂度等多个方面, 并生成详细的报…