Inhaltsverzeichnis
准备工作" >准备工作
TypeScript里的泛型是个啥" >TypeScript里的泛型是个啥
在VSCode中配置TypeScript" >在VSCode中配置TypeScript
找到问题" >找到问题
理解中心思想" >理解中心思想
使用泛型" >使用泛型
泛型约束" >泛型约束
为什么是泛型" >为什么是泛型
其他资源" >其他资源
结论" >结论
Heim Web-Frontend js-Tutorial Verstehen Sie das Konzept und die Verwendung von Generika in TypeScript

Verstehen Sie das Konzept und die Verwendung von Generika in TypeScript

Dec 31, 2020 pm 05:18 PM
javascript typescript 泛型

Verstehen Sie das Konzept und die Verwendung von Generika in TypeScript

本文介绍TypeScript中泛型(Generics)的概念和用法,它为什么重要,及其使用场景。我们会以一些清晰的例子,介绍其语法,类型和如何构建参数。你可以在你的集成开发环境中跟着实践。

准备工作

要从本文中跟着学习的话,你需要在电脑上准备以下东西:

  • 安装Node.js:你可以运行命令行检查Node是否安装好了。
node -v
Nach dem Login kopieren
  • 安装Node Package Manager: 通常安装Node时,它会顺带安装好所需版本的NPM。
  • 安装TypeScript:如果你安装好了Node Package Manager,你可以用以下命令在本机的全局环境安装TypeScript。
  • npm install -g typescript
    Nach dem Login kopieren
    集成开发环境:本文将使用微软团队开发的Visual Studio Code。可以在这里下载。进入其下载的目录,并按照提示进行安装。记得选择“添加打开代码”(Add open with code)选项,这样你就可以在本机从任何位置轻松打开VS Code了。

本文是写给各层次的TypeScript开发人员的,包括但并不只是初学者。 这里给出了设置工作环境的步骤,是为了照顾那些TypeScript和Visual Studio Code的新手们。

TypeScript里的泛型是个啥

在TypeScript中,泛型是一种创建可复用代码组件的工具。这种组件不只能被一种类型使用,而是能被多种类型复用。类似于参数的作用,泛型是一种用以增强类(classes)、类型(types)和接口(interfaces)能力的非常可靠的手段。这样,我们开发者,就可以轻松地将那些可复用的代码组件,适用于各种输入。然而,不要把TypeScript中的泛型错当成any类型来使用——你会在后面看到这两者的不同。

类似C#和Java这种语言,在它们的工具箱里,泛型是创建可复用代码组件的主要手段之一。即,用于创建一个适用于多种类型的代码组件。这允许用户以他们自己的类使用该泛型组件。

在VSCode中配置TypeScript

在计算机中创建一个新文件夹,然后使用VS Code 打开它(如果你跟着从头开始操作,那你已经安装好了)。

在VS Code中,创建一个app.ts文件。我的TypeScript代码都会放在这里面。

把下面打日志的代码拷贝到编辑器中:

console.log("hello TypeScript");
Nach dem Login kopieren

按下F5键,你会看到一个像这样的launch.json文件:

{
  // 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"
      ]
    }
  ]
}
Nach dem Login kopieren

里面的name字段的值,本来是Launch Program,我把它改成了TypeScript。你可以把它改成其他值。

点击Terminal Tab,选择Run Tasks,再选择一个Task Runner:"TypeScript Watch Mode",然后会弹出一个tasks.json文件,把它改成下面像这样:

 {
  // 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
   }
  ]
 }
Nach dem Login kopieren

app.ts所在的目录,创建另一个文件tsconfig.json。把下面的代码拷贝进去:

{
  "compilerOptions": {
    "sourceMap": true
  }
}
Nach dem Login kopieren

这样,Task Runner就可以把TypeScript编译成JavaScript,并且可监听到文件的变化,实时编译。

再次点击Ternimal标签,选择Run Build Task,再选择tsc: watch - tsconfig.json,可以看到终端出现的信息:

[21:41:31] Starting compilation in watch mode…
Nach dem Login kopieren

你可以使用VS Code的调试功能编译TypeScript文件。  

Verstehen Sie das Konzept und die Verwendung von Generika in TypeScript

设置好了开发环境,你就可以着手处理TypeScript泛型概念相关的问题了。

找到问题

TypeScript中不建议使用any类型,原因有几点,你可以在本文看到。其中一个原因,就是调试时缺乏完整的信息。而选择VS Code作为开发工具的一个很好的理由,就是它带来的基于这些信息的智能感知。

如果你有一个类,存储着一个集合。有方法向该集合里添加东西,也有方法通过索引获取集合里的东西。像这样:

class Collection {
  private _things: string[];
  constructor() {
    this._things = [];
  }
  add(something: string) {
    this._things.push(something);
  }
  get(index: number): string {
    return this._things[index];
  }
}
Nach dem Login kopieren

你可以很快辨识出,此集合被显示定义为一个string类型的集合,显然是不能在其中使用number的。如果想要处理number的话,可以创建一个接受number而不是string的集合。着是一个不错的选择,但有一个很大的缺点——代码重复。代码重复,最终会导致编写和调试代码的时间增多,并且降低内存的使用效率。

另一个选择,是使用any类型代替string类型定义刚才的类,像下面这样:

class Collection {
  private _things: any[];
  constructor() {
    this._things = [];
  }
  add(something: any) {
    this._things.push(something);
  }
  get(index: number): any {
    return this._things[index];
  }
}
Nach dem Login kopieren

此时,该集合支持你给出的任何类型。如果你创建像这样的逻辑构建此集合的话:

let Stringss = new Collection();
Stringss.add("hello");
Stringss.add("world");
Nach dem Login kopieren

这添加了字符串"hello"和"world"到集合中,你可以打出像length这样的属性,返回任意一个集合元素的长度。  

console.log(Stringss.get(0).length);
Nach dem Login kopieren

字符串"hello"有五个字符,运行TypeScript代码,你可以在调试模式下看到它。  

Verstehen Sie das Konzept und die Verwendung von Generika in TypeScript

请注意,当你鼠标悬停在length属性上时,VS Code的智能感知没有提供任何信息,因为它不知道你选择使用的确切类型。当你像下面这样,把其中一个添加的元素修改为其他类型时,比如number,这种不能被智能感知到的情况会体现得更加明显:

let Strings = new Collection();
Strings.add(001);
Strings.add("world");
console.log(Strings.get(0).length);
Nach dem Login kopieren

你打出一个undefined的结果,仍然没有什么有用信息。如果你更进一步,决定打印string的子字符串——它会报运行时错误,但不指不出任何具体的内容,更重要的是,编译器没有给出任何类型不匹配的编译时错误。  

console.log(Stringss.get(0).substr(0,1));
Nach dem Login kopieren

Verstehen Sie das Konzept und die Verwendung von Generika in TypeScript

这仅仅是使用any类型定义该集合的一种后果罢了。

理解中心思想

刚才使用any类型导致的问题,可以用TypeScript中的泛型来解决。其中心思想是类型安全。使用泛型,你可以用一种编译器能理解的,并且合乎我们判断的方式,指定类、类型和接口的实例。正如在其他强类型语言中的情况一样,用这种方法,就可以在编译时发现你的类型错误,从而保证了类型安全。

泛型的语法像这样:

function identity<T>(arg: T): T {
  return arg;
}
Nach dem Login kopieren

你可以在之前创建的集合中使用泛型,用尖括号括起来。  

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));
Nach dem Login kopieren

如果将带有尖括号的新逻辑复制到代码编辑器中,你会立即注意到"001"下的波浪线。这是因为,TypeScript现在可以从指定的泛型类型推断出001不是字符串。在T出现的地方,就可以使用string类型,这就实现了类型安全。本质上,这个集合的输出可以是任何类型,但你指明了它应该是string类型,所以编译器推断它就是string类型。这里使用的泛型声明是在类级别,它也可以在其他级别定义,如静态方法级别和实例方法级别,你稍后会看到。

使用泛型

你可以在泛型声明中,包含多个类型参数,它们只需要用逗号分隔,像这样:

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);
  }
}
Nach dem Login kopieren

声明时,类型参数也可以在函数中显式使用,比如:

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];
  }
}
Nach dem Login kopieren

因此,当你要创建一个新的集合时,在方法级别声明的泛型,现在也会在方法调用级别中被指示,像这样:  

let Stringss = new Collection();
Stringss.add<string>("hello");
Stringss.add("world");
Nach dem Login kopieren

你还可注意到,在鼠标悬停时,VS Code智能感知能够推断出第二个add函数调用仍然是string类型。

泛型声明同样适用于静态方法:

static add<A>(something: A): void {
  _things.push(something);
}
Nach dem Login kopieren

虽然初始化静态方法时,可使用泛型类型,但是,对初始化静态属性则不能。

泛型约束

现在,你已经对泛型有比较好的认识,是时候提到泛型的核心缺点及其实用的解决方案了。使用泛型,许多属性的类型都能被TypeScript推断出来,然而,在某些TypeScript不能做出准确推断的地方,它不会做任何假设。为了类型安全,你需要将这些要求或者约束定义为接口,并在泛型初始化中继承它们。

如果你有这样一个非常简单的函数:

function printName<T>(arg: T) {
  console.log(arg.length);
  return arg;
}
printName(3);
Nach dem Login kopieren

因为TypeScript无法推断出arg参数是什么类型,不能证明所有类型都具有length属性,因此不能假设它是一个字符串(具有length属性)。所以,你会在length属性下看到一条波浪线。如前所述,你需要创建一个接口,让泛型的初始化可以继承它,以便编译器不再报警。  

interface NameArgs {
  length: number;
}
Nach dem Login kopieren

你可以在泛型声明中继承它:

function printName<T extends NameArgs>(arg: T) {
  console.log(arg.length);
  return arg;
}
Nach dem Login kopieren

这告诉TypeScript,可使用任何具有length属性的类型。 定义它之后,函数调用语句也必须更改,因为它不再适用于所有类型。 所以它应看起来是这样:

printName({length: 1, value: 3});
Nach dem Login kopieren

这是一个很基础的例子。但理解了它,你就能看到在使用泛型时,设置泛型约束是多么有用。

为什么是泛型

一个活跃于Stack Overflow社区的成员,Behrooz,在后续内容中很好的回答了这个问题。在TypeScript中使用泛型的主要原因是使类型,类或接口充当参数。 它帮助我们为不同类型的输入重用相同的代码,因为类型本身可用作参数。

泛型的一些好处有:

  • 定义输入和输出参数类型之间的关系。比如
function test<T>(input: T[]): T {
  //… 
}
Nach dem Login kopieren

允许你确保输入和输出使用相同的类型,尽管输入是用的数组。

  • 可使用编译时更强大的类型检查。在上诉示例中,编译器让你知道数组方法可用于输入,任何其他方法则不行。
  • 你可以去掉不需要的强制类型转换。比如,如果你有一个常量列表:
Array<Item> a = [];
Nach dem Login kopieren

变量数组时,你可以由智能感知访问到Item类型的所有成员。

其他资源

结论

你已经看完了泛型概念的概述,并看到了各种示例来帮助揭示它背后的思想。 起初,泛型的概念可能令人困惑,我建议,把本文再读一遍,并查阅本文所提供的额外资源,帮助自己更好地理解。泛型是一个很棒的概念,可以帮助我们在JavaScript中,更好地控制输入和输出。请快乐地编码吧!

更多编程相关知识,请访问:编程教学!!

Das obige ist der detaillierte Inhalt vonVerstehen Sie das Konzept und die Verwendung von Generika in TypeScript. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
4 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Lösen generische Funktionen das Problem der variadischen Parametertypen in Golang? Lösen generische Funktionen das Problem der variadischen Parametertypen in Golang? Apr 16, 2024 pm 06:12 PM

Generische Funktionen in Go lösen das Problem variadischer Typen: Generische Funktionen ermöglichen die Angabe von Typparametern zur Laufzeit. Dadurch ist es möglich, Funktionen zu schreiben, die Parameter unterschiedlichen Typs verarbeiten können. Beispielsweise ist die Max-Funktion eine generische Funktion, die zwei vergleichbare Parameter akzeptiert und den größeren Wert zurückgibt. Durch die Verwendung generischer Funktionen können wir flexibleren und allgemeineren Code schreiben, der verschiedene Parametertypen verarbeiten kann.

Spezifische Anwendungsszenarien von Generika in Golang Spezifische Anwendungsszenarien von Generika in Golang May 04, 2024 am 11:45 AM

Anwendungsszenarien von Generika in Go: Erfassungsvorgänge: Erstellen Sie Erfassungsvorgänge, die für jeden Typ geeignet sind, z. B. zum Filtern. Datenstrukturen: Schreiben Sie allgemeine Datenstrukturen wie Warteschlangen, Stapel und Karten, um verschiedene Datentypen zu speichern und zu bearbeiten. Algorithmen: Schreiben Sie allgemeine Algorithmen wie Sortieren, Suchen und Reduzieren, die verschiedene Datentypen verarbeiten können.

Was sind die Ober- und Untergrenzen von Java-Funktionsgenerika? wie benutzt man? Was sind die Ober- und Untergrenzen von Java-Funktionsgenerika? wie benutzt man? Apr 26, 2024 am 11:45 AM

Generische Java-Funktionen ermöglichen das Festlegen von Ober- und Untergrenzen. Extends gibt an, dass der von einer Funktion akzeptierte oder zurückgegebene Datentyp ein Untertyp des angegebenen Typs sein muss, z. B. Die untere Grenze (super) gibt an, dass der von einer Funktion akzeptierte oder zurückgegebene Datentyp ein Supertyp des angegebenen Typs sein muss, z. B. Die Verwendung von Generika verbessert die Wiederverwendbarkeit und Sicherheit des Codes.

Welche Einschränkungen gibt es bei generischen Funktionen in Golang? Welche Einschränkungen gibt es bei generischen Funktionen in Golang? Apr 16, 2024 pm 05:12 PM

Einschränkungen der generischen Go-Funktionen: Es werden nur Typparameter unterstützt, Wertparameter werden nicht unterstützt. Funktionsrekursion wird nicht unterstützt. Typparameter können nicht explizit angegeben werden, sie werden vom Compiler abgeleitet.

Welchen Einfluss haben Golang-Generika auf Funktionssignaturen und Parameter? Welchen Einfluss haben Golang-Generika auf Funktionssignaturen und Parameter? Apr 17, 2024 am 08:39 AM

Zu den Auswirkungen von Generika auf Go-Funktionssignaturen und -Parameter gehören: Typparameter: Funktionssignaturen können Typparameter enthalten, die die Typen angeben, die die Funktion verwenden kann. Typeinschränkungen: Typparameter können Einschränkungen haben, die Bedingungen angeben, die sie erfüllen müssen. Parametertyp-Inferenz: Der Compiler kann auf den Typ nicht spezifizierter Typparameter schließen. Angeben von Typen: Parametertypen können explizit angegeben werden, um generische Funktionen aufzurufen. Dies erhöht die Wiederverwendbarkeit und Flexibilität des Codes und ermöglicht Ihnen das Schreiben von Funktionen und Typen, die mit mehreren Typen verwendet werden können.

Wie funktionieren Java-Enum-Typen mit Generika? Wie funktionieren Java-Enum-Typen mit Generika? May 04, 2024 am 08:36 AM

Die Kombination von Aufzählungstypen und Generika in Java: Wenn Sie eine Aufzählung mit Generika deklarieren, müssen Sie spitze Klammern hinzufügen, und T ist der Typparameter. Wenn Sie eine generische Klasse erstellen, müssen Sie auch spitze Klammern hinzufügen. T ist ein Typparameter, der jeden Typ speichern kann. Diese Kombination verbessert die Codeflexibilität, die Typsicherheit und vereinfacht den Code.

Können Golang-Variablenparameter in generischen Funktionen verwendet werden? Können Golang-Variablenparameter in generischen Funktionen verwendet werden? Apr 29, 2024 pm 02:06 PM

In Go können variadische Parameter für generische Funktionen verwendet werden, wodurch generische Funktionen erstellt werden können, die eine variable Anzahl von Parametern akzeptieren und für mehrere Typen geeignet sind. Sie können beispielsweise eine generische Funktion Mode erstellen, die das häufigste Element in einer bestimmten Liste findet: Mode akzeptiert eine variable Anzahl von Elementen vom Typ T. Es zählt Elemente, indem es Zählungen für jedes Element erstellt. Dann findet es das Element, das am häufigsten vorkommt, und gibt es als Modus zurück. In der Hauptfunktion können Sie die Funktion „Mode“ für die Liste der Zeichenfolgen und die Liste der Ganzzahlen aufrufen, die jeweils die Zeichenfolge und die Zahl mit den meisten Vorkommen zurückgibt.

Wie kann ich Typparameter in generischen Java-Methoden einschränken? Wie kann ich Typparameter in generischen Java-Methoden einschränken? Apr 30, 2024 pm 01:30 PM

Um Typparameter in einer generischen Java-Methode einzuschränken, verwenden Sie die Syntax, bei der Bound der Typ oder die Schnittstelle ist. Daher akzeptieren Parameter nur Typen, die von Bound erben oder die Bound-Schnittstelle implementieren. Beschränken Sie beispielsweise T auf einen Typ, der mit sich selbst vergleichbar ist.

See all articles