Typescript中泛型的使用
什么是TypeScript?
TypeScript是一种开源的编程语言,它是JavaScript的超集。其添加了静态类型检查和其他一些特性,以提供更好的开发工具和代码质量。TypeScript代码可以通过编译器转换为JavaScript代码,然后在任何支持JavaScript的环境中运行。
TypeScript的主要特性包括:
- 静态类型检查:TypeScript可以在编译时捕获类型错误,提供更好的代码质量和可维护性。
- 类型注解:可以为变量、函数参数和返回值等添加类型注解,以提供更明确的类型信息。
- 类和接口:TypeScript支持面向对象编程,可以定义类和接口,并实现继承和多态等概念。
- 泛型:可以使用泛型来提供更灵活的类型支持,以处理不同类型的数据。
- ES6+支持:TypeScript支持ECMAScript 6及以上版本的语法和特性。
- 工具和生态系统:TypeScript拥有丰富的工具和生态系统,包括编辑器插件、开发工具和第三方库等。
TypeScript广泛用于Web开发和Node.js开发,特别是在大型项目和团队中。它提供了更好的代码组织和维护性,并且可以与JavaScript库和框架无缝集成。
什么是泛型?
在编程中,常常会遇到需要在多个地方使用相同的逻辑,但操作的数据类型可能不同的情况。泛型则提供了一种通用的方式来处理这种情况。它允许我们在定义函数、类或接口时使用类型参数,以便在使用时指定具体的类型。
泛型语法
function pickObjectKeys(obj, keys) {
let result = {}
for (const key of keys) {
if (key in obj) {
result[key] = obj[key]
}
}
return result
}
此代码段显示了 pickObjectKeys() 函数,该函数遍历keys数组并使用数组中指定的键创建一个新对象。
如何使用该函数:
const language = {
name: "TypeScript",
age: 8,
extensions: ['ts', 'tsx']
}
const ageAndExtensions = pickObjectKeys(language, ['age', 'extensions'])
这声明了一种对象,然后使用 pickObjectKeys() 函数隔离 age 和 extensions 属性。 ageAndExtensions 的值如下:
{
age: 8,
extensions: ['ts', 'tsx']
}
如果要将此代码迁移到 TypeScript 以使其类型安全,则必须使用泛型。 我们可以通过添加以下突出显示的行来重构代码:
function pickObjectKeys<T, K extends keyof T>(obj: T, keys: K[]) {
let result = {} as Pick<T, K>
for (const key of keys) {
if (key in obj) {
result[key] = obj[key]
}
}
return result
}
const language = {
name: "TypeScript",
age: 8,
extensions: ['ts', 'tsx']
}
const ageAndExtensions = pickObjectKeys(language, ['age', 'extensions'])
<T, K extends keyof T> 为函数声明了两个参数类型,其中 K 被分配一个类型,该类型是 T 中的key的并集。 然后将 obj 函数参数设置为 T 表示的任何类型,并将key设置为数组, 无论 K 代表什么类型。
泛型的类型约束
默认情况下,泛型函数的类型变量 Type 可以代表任意类型,这导致,无法访问任何属性
function id<Type>(value: Type): Type {
// 报错: 类型“Type”上不存在属性“length”
console.log(value.length)
return value
}
id<string>('a')
Type 可以代表任意类型,无法保证一定存在 length 属性,比如 number 类型就没有 length 此时,就需要为泛型添加约束来收缩类型(缩窄类型取值范围)
1. 添加约束
比如,想要访问参数 value 的 length 属性,就可以添加以下约束:
// 创建一个接口
// interface ILength { length: number }
type Length = { length: number }
// Type extends Length 添加泛型约束
// 表示传入的 类型 必须满足 Length 类型的要求才行,也就是得有一个 number 类型的 length 属性
function id<Type extends Length>(value: Type): Type {
console.log(value.length)
return value
}
2. 多个类型变量
泛型的类型变量可以有多个,并且类型变量之间还可以约束(比如,第二个类型变量受第一个类型变量约束)
比如,创建一个函数来获取对象中属性的值:
function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
let person = { name: 'jack', age: 18 }
getProp(person, 'name')
- 添加了第二个类型变量Key,两个类型变量之间使用,逗号分隔。
- keyof 关键字接收一个对象类型,生成其键名称(可能是字符串或数字)的联合类型。
- 本示例中keyof Type实际上获取的是 person 对象所有键的联合类型,也就是:‘name’ | ‘age’
- 类型变量Key受Type约束,可以理解为:Key只能是Type所有键中的任意一个,或者说只能访问对象中存在的属性。
第一个参数也可以添加类型约束,比如:
// Type extends object 表示: Type 应该是一个对象类型,如果不是 对象 类型,就会报错
function getProperty<Type extends object, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key]
}
泛型是TypeScript中一个强大的特性,它可以增加代码的灵活性和安全性。我们可以在函数、类和接口中使用泛型,并使用类型约束来限制泛型参数的类型范围。