Typescript 函数声明中的尖括号“<>”是什么意思?

Mic*_*l P 3 typescript

我知道在 TypeScript 中用尖括号“<>”括起来的类是什么意思中有一个几乎类似的问题

但是当我发现它以一种复杂的(对于新手)方式用于在接口内声明函数时,它仍然让我感到困惑。

getContent<K extends keyof ContentMap>(content: K, conf?: ContentMap[K]["conf"]): Promise<Readonly<ContentMap[K]["content"]>>;
Run Code Online (Sandbox Code Playgroud)

尖括号多次使用(甚至递归)。我怎样才能阅读它?

geo*_*org 15

当你学习 Typescript 时,你实际上学习的不是一种语言,而是两种。第一种语言是 Typescript 本身,它是带有类型注释和一些扩展的 Javascript,例如“枚举”或“公共/私有”类成员。第二种语言是类型语言。它没有正式名称,我们以发明家安德斯·海尔斯伯格( Anders Hejlsberg) 的名字命名为安德斯

Anders 的目的是为您的程序生成动态类型。Typescript 处理字符串、数字、对象等值,而 Anders 只处理一种数据:类型本身。安德斯的价值观是类型。Anders 中的函数接受一个或多个类型参数并返回另一种类型。

每次<>在程序中使用时,实际上是在编写 Anders 代码,而不是 Typescript 代码。可以MyType<T>通过类型推断显式调用此代码(当您编写类似的内容时)或在后台调用。

例如,这是一个 Typescript 函数,它接受两个值并根据它们返回另一个值:

function pair (x, y) {
    return [x, y]
}
Run Code Online (Sandbox Code Playgroud)

这是一个 Anders 函数,它接受两种类型并基于它们返回另一种类型:

type Pair<U, V> = [U, V]
Run Code Online (Sandbox Code Playgroud)

在 Typescript 中,如果你给出pair两个值,你会得到一个包含这两个值的数组。

在 Anders 中,如果您给出Pair number(不是任何数字,“数字”类型)和string,您将返回[number, string],它是所有可能number,string数组的类型,例如[1, "hi"][3.14, "hey"]。如果你给它stringand boolean,你会得到所有数组的类型,比如["hi", true], ["blah", false]

与其他语言一样,Anders 提供了基本的编程结构(概括地说,所有这些都是类型或作用于类型,而不是值):

  • 内置类型,如number, string, any, {}。这些类似于 Typescript 内置对象,如“Number”或“String”。

  • 文字,如"foo". 这些类似于 Typescript 中的文字,但在 TS 中"foo"表示特定字符​​串,例如字符序列f, o, o,而在 Anders 中则表示一种类型,即“所有 foo 字符串的类型”,显然只有一个可能的成员,"foo"

  • 联合,类似于 TS: 中的数组A|B|C

  • 结构,类似于 TS 中的对象。在 TS 中,对象将字符串映射到值。在 Anders 中,一个结构(又名“映射类型”)将类型映射到其他类型。索引运算符S[B]返回结构S映射到的类型B

        {foo: string; bar:number}["foo"]` ====> string
    
    Run Code Online (Sandbox Code Playgroud)
  • 运算符,例如一元运算keyof符接受一个类型A并返回 的所有可能键的类型A,即联合(数组)TypeOfKey1 | TypeOfKey2 | ...

        keyof {foo:string, bar:number} =====> "foo"|"bar"
    
    Run Code Online (Sandbox Code Playgroud)
  • 比较,就像a > b在 TS 中一样。Anders 只有一种比较形式,A extends B,这意味着它A是 的子集B,也就是说,该类型的所有可能值A也是 的值B,但反过来不一定。

        "foo" extends string =====> ok
        "foo" extends "foo"|"bar" =====> ok
        "blag" extends "foo"|"bar" =====> not ok
    
    Run Code Online (Sandbox Code Playgroud)
  • 条件: comparison ? Type1 : Type2

  • 循环,如{[A in SomeUnion]: T}。这将创建一个结构,其键是联合成员,值是 T 类型

        {[A in "foo"|"bar"]: number} =====> {foo:number, bar:number}
    
    Run Code Online (Sandbox Code Playgroud)
  • 函数调用,它们是 SomeOtherTypeDeclaration<Type1, Type2, ...>

  • 最后,Anders 还对输入参数进行了类型检查,类似于function foo(x:number)Typescript。在 Anders 中,类型检查是一种比较,即A extends B

现在,回到您的示例(为清晰起见进行了简化)。

interface A {}
interface B {}
interface C {}
interface D {}

type ContentMap = {
  foo: {
      conf: A
      content: B
  },
  bar: {
      conf: C
      content: D
  }
}

function getContent<K extends keyof ContentMap>
  ( content: K,
    conf?: ContentMap[K]["conf"]
  ): Readonly<ContentMap[K]["content"]> {
      ...
  }
Run Code Online (Sandbox Code Playgroud)

getContent是安德斯功能,它接受一个K型,并返回另一种类型(X, Y) => Z,这是一种类型的具有类型两个参数的所有功能XY和返回值的类型的Z

让我们用不同的类型手动“调用”这个函数,看看会发生什么。

  1. getContent<number>. 首先,Anders 检查参数的类型。我们的类型检查是extends keyof ContentMap. 正如我们所记得的,keyof ContentMap返回一个 的键数组ContentMap,也就是"foo"|"bar"where"foo""bar"是类型,而不仅仅是字符串。然后,我们的论点number, 被检查"foo"|"bar"。显然,number不是这种类型的子集,所以类型检查失败,我们得到一个错误。

  2. getContent<"foo">. 类型检查成功(因为"foo" 的子集"foo"|"bar"),我们可以继续。我们的任务是基于 构造函数类型"foo"。第一个参数的类型K与参数相同,所以它变成了 just "foo"。第二个参数两次应用索引运算符:首先,我们评估ContentMap["foo"],它给出了我们{conf: A, content: B},然后我们应用["conf"],它给出了我们A。以类似的方式,我们获得B返回类型。最后,我们调用内置的 Anders 函数Readonly并返回另一种类型,让我们调用它ReadonlyB,所以,我们得到的是函数类型(content: "foo", conf: A) => ReadonlyB,这就是我们的 Anders 函数返回的内容。

  3. getContent<"bar"> ...留下作为练习。

现在,当你写这个时会发生什么?

let something = getContent('foo', {...})
Run Code Online (Sandbox Code Playgroud)

编译器看到您有一些 Anders 代码,与getContent该代码相关并评估该代码,并将其"foo"作为参数传递。如上所示,返回类型将为("foo", A) => ReadonlyB. 然后,针对这种类型检查上面的行,如果不匹配则失败,这基本上就是整个事情的全部内容。

希望这可以帮助...


Soc*_*Soc 9

正如@axiac 提到的,它与泛型有关。

您可以阅读它的方式是考虑type

例子:

// generic class that deals with type T
class List<T> {}

// usage
const list1 = new List<string>() // list of type string
const list2 = new List<number>() // list of type number
const list3 = new List<any>()    // list of type any
Run Code Online (Sandbox Code Playgroud)

  • 这比那个超长接受的答案更容易理解,谢谢! (3认同)