泛型的由来
如果想要创建可处理多种类型而不只是一种类型的组件,该怎么操作? 可以使用 any 类型,但这样就失去了 TypeScript 类型检查系统的功能。
泛型的特点
-
(「可复用行性」) 泛型是可以在代码库中定义和重复使用的代码模板。 -
(「定义时指示性」) 它们提供了一种方法,可用于指示函数、类或在调用接口时要使用的类型。 -
(「调用时指示性」) 可以通过将参数传递给函数的方式来理解,不同之处是使用泛型可以指示组件在被调用时应该使用哪种类型。
使用时机
当代码是满足以下条件的函数或类时,创建泛型函数:
-
处理各种数据类型。 在多个位置使用该数据类型。 泛型可以:
-
在处理类型时提供更大的灵活性。 -
实现代码重用。 -
减少使用 any 类型的需要。
示例 :getArray 函数生成 any 类型的项的数组
// 使用any 传入任何参数 并返回任何参数
function getArray(items: any[]): any[] {
return new Array().concat(items);
}
let numberArray = getArray([5, 10, 15, 20]);
let stringArray = getArray(['Cats', 'Dogs', 'Birds']);
numberArray.push(25); // OK
stringArray.push('Rabbits'); // OK
numberArray.push('This is not a number'); // OK
stringArray.push(30); // OK
console.log(numberArray); // [5, 10, 15, 20, 25, "This is not a number"]
console.log(stringArray); // ["Cats", "Dogs", "Birds", "Rabbits", 30]
上面是 any 类型 没有类型检查等 ,如果想要在调用函数时确定数组将包含的值的类型,然后让 TypeScript 对传递给它的值进行类型检查以确保它们属于该类型,该怎么操作? 这时泛型就可以发挥作用了。
泛型函数定义
使用泛型重写 getArray 函数。 现在,它可以接受你在调用函数时指定的任何类型。
function getArray<T>(items: T[]): T[] {
return new Array<T>().concat(items);
}
-
泛型定义一个或多个“类型变量”来标识要传递给组件的一个或多个类型(用尖括号 (< >) 括起来) -
函数中的类型变量称为 。 T 是泛型的常用名称,但可以根据需要对其进行命名。 -
指定类型变量后,可以使用它来代替参数类型、返回类型或将其置于函数中要添加类型批注的任何其他位置。
调用泛型函数
若要调用函数并向其传递类型,请将
-
例如,getArray
表示了 -
指示函数仅接受 number 值的数组 -
并返回 number 值的数组。 -
因为类型已指定为 number,所以 TypeScript 会预期将 number 值传递给函数,如果传递的是其他值,则会引发错误。
如果在调用函数时省略类型变量,TypeScript 将推断类型。 但是,这仅适用于简单数据。 如果传入数组或对象,会导致推断任何类型(any)并消除类型检查。
function getArray<T>(items: T[]): T[] {
return new Array<T>().concat(items);
}
let numberArray = getArray<number>([5, 10, 15, 20]);
numberArray.push(25); // OK
numberArray.push('This is not a number'); // 类型“string”的参数不能赋给类型“number”的参数。
let stringArray = getArray<string>(['Cats', 'Dogs', 'Birds']);
stringArray.push('Rabbits'); // OK
stringArray.push(30); // 类型“number”的参数不能赋给类型“string”的参数。
使用多个类型变量
泛型组件中并不是只能使用单个类型变量。
// 使用多个变量
function person11<T, U>(name: T, age: U): U {
console.log(age);
return age
}
let returnNumber = person11<string, number>('王大可1', 18);
let returnString = person11<string, string>('王大可2', '28');
let returnBoolean = person11<string, boolean>('王大可3', true);
returnNumber = returnNumber * 100; // OK
returnString = returnString * 100; // 错误 算术运算左侧必须是 "any"、"number"、"bigint" 或枚举类型
returnBoolean = returnBoolean * 100; // 错误 算术运算左侧必须是 "any"、"number"、"bigint" 或枚举类型
使用泛型类型的方法和属性
上面的T,U 非常宽泛,导致无法再函数内部无法使用变量。 使用类型变量创建泛型组件时,只能使用每种类型可用的对象的属性和方法。 防止参数不兼容的操作引起错误。
function person11<T, U>(name: T, age: U): U {
let result: T = name + name; // Error 运算符“+”不能应用于类型“T”和“T”
console.log(age);
return age
}
使用泛型约束来限制类型
为了解决上面的问题故而限制类型变量的变量范围
-
自定义 type 声明为元组 然后使用自定义类型 extend 类型变量 -
类型限制为另一个对象的属性
//自定义 type 声明为元组
type LimitTypes = string | number;
function person11<T extends LimitTypes, U>(name: T, age: U): U {
let result: T = name + name; // Error 运算符“+”不能应用于类型“T”和“T”
console.log(age);
return age
}
// 类型限制为另一个对象的属性
function getPets<T, K extends keyof T>(pet: T, key: K) {
return pet[key];
}
let pets1 = { cats: 4, dogs: 3, parrots: 1, fish: 6 };
let pets2 = { 1: "cats", 2: "dogs", 3: "parrots", 4: "fish" }
console.log(getPets(pets1, "fish")); // 输出 6
console.log(getPets(pets2, "3")); // Error 类型“"3"”的参数不能赋给类型“4 | 3 | 1 | 2”的参数。
对泛型使用类型保护
在上面的例子中 虽然限定了泛型类型 LimitTypes 但是还是不能执行操作,这时可以使用类型保护来处理逻辑。
function person11<T, U extends LimitTypes>(name: T, age: U) {
// let result: T = name + name; // Error 运算符“+”不能应用于类型“T”和“T”
let result: LimitTypes = '';
let typeValue: string = typeof age;
if (typeof age === 'number') { // Is it a number?
result = age + age; // OK
} else if (typeof age === 'string') { // Is it a string?
result = age + age; // OK
}
console.log(`年龄是 ${age} 类型是 ${typeValue} 返回是 ${result}`);
console.log(age);
return result
}
let returnNumber = person11<string, number>('王大可1', 18);
let returnString = person11<string, string>('王大可2', '28');
只能使用 typeof 类型保护来检查基元类型 string、number、bigint、function、boolean、symbol、object 和未定义类型。 若要检查类的类型,请使用 instanceof 类型保护。
原文始发于微信公众号(王大可996):TypeScript学习笔记(10)-泛型
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/205211.html