本文介绍TypeScript中泛型(Generics)的概念和用法,它为什么重要,及其使用场景。我们会以一些清晰的例子,介绍其语法,类型和如何构建参数。你可以在你的集成开发环境中跟着实践。
|
本文介绍TypeScript中泛型(Generics)的概念和用法,它为什么重要,及其使用场景。我们会以一些清晰的例子,介绍其语法,类型和如何构建参数。你可以在你的集成开发环境中跟着实践。 准备工作要从本文中跟着学习的话,你需要在电脑上准备以下东西:
node -v
本文是写给各层次的TypeScript开发人员的,包括但并不只是初学者。 这里给出了设置工作环境的步骤,是为了照顾那些TypeScript和Visual Studio Code的新手们。 TypeScript里的泛型是个啥在TypeScript中,泛型是一种创建可复用代码组件的工具。这种组件不只能被一种类型使用,而是能被多种类型复用。类似于参数的作用,泛型是一种用以增强类(classes)、类型(types)和接口(interfaces)能力的非常可靠的手段。这样,我们开发者,就可以轻松地将那些可复用的代码组件,适用于各种输入。然而,不要把TypeScript中的泛型错当成 类似C#和Java这种语言,在它们的工具箱里,泛型是创建可复用代码组件的主要手段之一。即,用于创建一个适用于多种类型的代码组件。这允许用户以他们自己的类使用该泛型组件。 在VSCode中配置TypeScript在计算机中创建一个新文件夹,然后使用VS Code 打开它(如果你跟着从头开始操作,那你已经安装好了)。 在VS Code中,创建一个 把下面打日志的代码拷贝到编辑器中: console.log("hello TypeScript");按下 {
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "TypeScript",
"program": "${workspaceFolder}\\app.ts",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}里面的 点击 {
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "echo",
"type": "shell",
"command": "tsc",
"args": ["-w", "-p","."],
"problemMatcher": [
"$tsc-watch"
],
"isBackground": true
}
]
}在 {
"compilerOptions": {
"sourceMap": true
}
}这样, 再次点击 [21:41:31] Starting compilation in watch mode… 你可以使用VS Code的调试功能编译TypeScript文件。
设置好了开发环境,你就可以着手处理TypeScript泛型概念相关的问题了。 找到问题TypeScript中不建议使用 如果你有一个类,存储着一个集合。有方法向该集合里添加东西,也有方法通过索引获取集合里的东西。像这样: class Collection {
private _things: string[];
constructor() {
this._things = [];
}
add(something: string) {
this._things.push(something);
}
get(index: number): string {
return this._things[index];
}
}你可以很快辨识出,此集合被显示定义为一个 另一个选择,是使用 class Collection {
private _things: any[];
constructor() {
this._things = [];
}
add(something: any) {
this._things.push(something);
}
get(index: number): any {
return this._things[index];
}
}此时,该集合支持你给出的任何类型。如果你创建像这样的逻辑构建此集合的话: let Stringss = new Collection();
Stringss.add("hello");
Stringss.add("world");这添加了字符串"hello"和"world"到集合中,你可以打出像 console.log(Stringss.get(0).length); 字符串"hello"有五个字符,运行TypeScript代码,你可以在调试模式下看到它。
请注意,当你鼠标悬停在length属性上时,VS Code的智能感知没有提供任何信息,因为它不知道你选择使用的确切类型。当你像下面这样,把其中一个添加的元素修改为其他类型时,比如 let Strings = new Collection();
Strings.add(001);
Strings.add("world");
console.log(Strings.get(0).length);你打出一个 console.log(Stringss.get(0).substr(0,1));
这仅仅是使用 理解中心思想刚才使用 泛型的语法像这样: function identity<T>(arg: T): T {
return arg;
}你可以在之前创建的集合中使用泛型,用尖括号括起来。 class Collection<T> {
private _things: T[];
constructor() {
this._things = [];
}
add(something: T): void {
this._things.push(something);
}
get(index: number): T {
return this._things[index];
}
}
let Stringss = new Collection<String>();
Stringss.add(001);
Stringss.add("world");
console.log(Stringss.get(0).substr(0, 1));如果将带有尖括号的新逻辑复制到代码编辑器中,你会立即注意到"001"下的波浪线。这是因为,TypeScript现在可以从指定的泛型类型推断出001不是字符串。在 使用泛型你可以在泛型声明中,包含多个类型参数,它们只需要用逗号分隔,像这样: class Collection<T, K> {
private _things: K[];
constructor() {
this._things = [];
}
add(something: K): void {
this._things.push(something);
}
get(index: number): T {
console.log(index);
}
}声明时,类型参数也可以在函数中显式使用,比如: class Collection {
private _things: any[];
constructor() {
this._things = [];
}
add<A>(something: A): void {
this._things.push(something);
}
get<B>(index: number): B {
return this._things[index];
}
}因此,当你要创建一个新的集合时,在方法级别声明的泛型,现在也会在方法调用级别中被指示,像这样: let Stringss = new Collection();
Stringss.add<string>("hello");
Stringss.add("world");你还可注意到,在鼠标悬停时,VS Code智能感知能够推断出第二个add函数调用仍然是 泛型声明同样适用于静态方法: static add<A>(something: A): void {
_things.push(something);
}虽然初始化静态方法时,可使用泛型类型,但是,对初始化静态属性则不能。 泛型约束现在,你已经对泛型有比较好的认识,是时候提到泛型的核心缺点及其实用的解决方案了。使用泛型,许多属性的类型都能被TypeScript推断出来,然而,在某些TypeScript不能做出准确推断的地方,它不会做任何假设。为了类型安全,你需要将这些要求或者约束定义为接口,并在泛型初始化中继承它们。 如果你有这样一个非常简单的函数: function printName<T>(arg: T) {
console.log(arg.length);
return arg;
}
printName(3);因为TypeScript无法推断出 interface NameArgs {
length: number;
}你可以在泛型声明中继承它: function printName<T extends NameArgs>(arg: T) {
console.log(arg.length);
return arg;
}这告诉TypeScript,可使用任何具有 printName({length: 1, value: 3});这是一个很基础的例子。但理解了它,你就能看到在使用泛型时,设置泛型约束是多么有用。 为什么是泛型一个活跃于Stack Overflow社区的成员,Behrooz,在后续内容中很好的回答了这个问题。在TypeScript中使用泛型的主要原因是使类型,类或接口充当参数。 它帮助我们为不同类型的输入重用相同的代码,因为类型本身可用作参数。 泛型的一些好处有:
function test<T>(input: T[]): T {
//…
}允许你确保输入和输出使用相同的类型,尽管输入是用的数组。
Array<Item> a = []; 变量数组时,你可以由智能感知访问到Item类型的所有成员。 其他资源
结论你已经看完了泛型概念的概述,并看到了各种示例来帮助揭示它背后的思想。 起初,泛型的概念可能令人困惑,我建议,把本文再读一遍,并查阅本文所提供的额外资源,帮助自己更好地理解。泛型是一个很棒的概念,可以帮助我们在JavaScript中,更好地控制输入和输出。请快乐地编码吧! 更多编程相关知识,请访问:编程教学!! 以上就是了解TypeScript中泛型(Generics)的概念和用法的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
