TypeScript 的 generic 函数

简介: TypeScript 的 generic 函数

官方链接


编写一个函数,其中输入的类型与输出的类型相关,或者两个输入的类型以某种方式相关。 让我们考虑一个返回数组第一个元素的函数:


function firstElement(arr: any[]) {
  return arr[0];
}

这个函数完成了它的工作,但不幸的是返回类型为 any。 如果函数返回数组元素的类型会更好。


在 TypeScript 中,当我们想要描述两个值之间的对应关系时,会使用泛型。 我们通过在函数签名中声明一个类型参数来做到这一点:


function firstElement<T>(arr: T[]): T {
  return arr[0];
}
const arr: string[] = ['1', '2', '3'];
const result = firstElement(arr);
console.log(result);
const result1:number = firstElement(arr);

image.png


TypeScript 的类型推断 - Type inference

function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
  return arr.map(func);
}

注意,上面代码的 Inout,Output 可以被 T, V 替代,但是可读性不如前者。


image.png


Type constrains - 类型约束

我们已经编写了一些可以处理任何类型值的通用函数。 有时我们想关联两个值,但只能对某个值的子集进行操作。 在这种情况下,我们可以使用约束来限制类型参数可以接受的类型种类。


让我们编写一个函数,返回两个值中较长的一个。 为此,我们需要一个长度属性,它是一个数字。 我们通过编写 extends 子句将类型参数限制为该类型:


function longest<Type extends { length: number }>(a: Type, b: Type) {
  if (a.length >= b.length) {
    return a;
  } else {
    return b;
  }
}
// longerArray is of type 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);
console.log(longerArray);
// longerString is of type 'string'
const longerString = longest("alice", "bob");
console.log(longerString);
// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);

最后一个函数调用会出现编译错误,因为 TypeScript 基本类型 number 并不存在名称为 length 的属性。


同 Java 相比,TypeScript 的类型约束的强大之处在于,extends 后面紧跟的不需要是 TypeScript 的 built-in type,比如本例里的:


{
length: number
}

意思是,只要该函数传入的类型,至少包含类型为 number 的 length 属性即可。


Specifying Type Arguments

TypeScript 通常可以在泛型调用中推断出预期的类型参数,但并非总是如此。 例如,假设您编写了一个函数来组合两个数组:

function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
  return arr1.concat(arr2);
}

编译错误:

image.png


解决办法:使用尖括号语法,显式传入类型参数:这里 T = string | number,意思是接收 string 或者 number 类型均可。

image.png

编写 generic 函数的最佳实践

编写泛型函数很有趣,而且很容易被类型参数冲昏头脑。 有太多类型参数或在不需要它们的地方使用约束会使推理不那么成功,使函数的调用者感到沮丧。


最佳实践1 - Push Type Parameters Down

function firstElement1<Type>(arr: Type[]) {
  return arr[0];
}
function firstElement2<Type extends any[]>(arr: Type) {
  return arr[0];
}
// a: number (good)
const a = firstElement1([1, 2, 3]);
// b: any (bad)
const b = firstElement2([1, 2, 3]);

乍一看,两种方法似乎相同,但 firstElement1 是编写此函数的更好方法。 它的推断返回类型是 Type,但 firstElement2 的推断返回类型是 any,因为 TypeScript 必须使用约束类型解析 arr[0] 表达式,而不是在调用期间“等待”解析元素。


最佳实践 2- Use Fewer Type Parameters

function filter1(arr: Type[], func: (arg: Type) => boolean): Type[] {

 return arr.filter(func);

}


function filter2 boolean>(

 arr: Type[],

 func: Func

): Type[] {

 return arr.filter(func);

}

1

2

3

4

5

6

7

8

9

10

我们创建了一个不关联两个值的类型参数 Func。 这总是一个危险信号,因为这意味着想要指定类型参数的调用者必须无缘无故地手动指定一个额外的类型参数。 Func 不会做任何事情,只会让函数更难阅读和推理!


最佳实践3 - Type Parameters Should Appear Twice

function greet(s: Str) {

 console.log("Hello, " + s);

}


greet("world");

1

2

3

4

5

这个例子里, Str 只出现了一次,因此根本毫无必要。


可以简写成:


function greet(s: string) {

 console.log("Hello, " + s);

}



相关文章
|
5月前
|
JavaScript 前端开发 编译器
TypeScript 函数第一章
TypeScript 函数第一章
50 4
|
4月前
|
JavaScript 前端开发 测试技术
[小笔记]TypeScript/JavaScript模拟Python中的Range函数
[小笔记]TypeScript/JavaScript模拟Python中的Range函数
29 0
|
3月前
|
JavaScript
【HarmonyOS 4.0 应用开发实战】TypeScript入门之声明、数据类型、函数、类的详讲
【HarmonyOS 4.0 应用开发实战】TypeScript入门之声明、数据类型、函数、类的详讲
45 0
|
3月前
|
JavaScript 前端开发 编译器
10分钟让你吃透 《TypeScript》 函数
TypeScript提供了丰富的函数类型定义方式,可以对函数参数、返回值进行类型注解,从而提供了更为强大的类型检查。
|
4月前
|
JavaScript 前端开发 编译器
TypeScript【可选属性、只读属性、额外的属性检查、函数类型、类类型、继承接口】(四)-全面详解(学习总结---从入门到深化)
TypeScript【可选属性、只读属性、额外的属性检查、函数类型、类类型、继承接口】(四)-全面详解(学习总结---从入门到深化)
26 0
|
4月前
|
JavaScript 前端开发 程序员
TypeScript【枚举、联合类型函数_基础、函数_参数说明 、类的概念、类的创建】(二)-全面详解(学习总结---从入门到深化)
TypeScript【枚举、联合类型函数_基础、函数_参数说明 、类的概念、类的创建】(二)-全面详解(学习总结---从入门到深化)
20 0
|
4月前
|
JavaScript 前端开发 API
2020你应该知道的TypeScript学习路线【函数类型】
2020你应该知道的TypeScript学习路线【函数类型】
32 0
|
5月前
|
JavaScript 前端开发 安全
详细介绍 TypeScript 函数的各种特性、用法和最佳实践
详细介绍 TypeScript 函数的各种特性、用法和最佳实践
54 3
|
5月前
|
JavaScript 前端开发 编译器
TypeScript 函数 第三章
TypeScript 函数 第三章
22 0
|
5月前
|
JavaScript 前端开发 编译器
TypeScript 函数 第二章
TypeScript 函数 第二章
37 0