我知道在 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,这是一种类型的具有类型两个参数的所有功能X和Y和返回值的类型的Z。
让我们用不同的类型手动“调用”这个函数,看看会发生什么。
getContent<number>. 首先,Anders 检查参数的类型。我们的类型检查是extends keyof ContentMap. 正如我们所记得的,keyof ContentMap返回一个 的键数组ContentMap,也就是"foo"|"bar"where"foo"和"bar"是类型,而不仅仅是字符串。然后,我们的论点number, 被检查"foo"|"bar"。显然,number不是这种类型的子集,所以类型检查失败,我们得到一个错误。
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 函数返回的内容。
getContent<"bar"> ...留下作为练习。
现在,当你写这个时会发生什么?
let something = getContent('foo', {...})
Run Code Online (Sandbox Code Playgroud)
编译器看到您有一些 Anders 代码,与getContent该代码相关并评估该代码,并将其"foo"作为参数传递。如上所示,返回类型将为("foo", A) => ReadonlyB. 然后,针对这种类型检查上面的行,如果不匹配则失败,这基本上就是整个事情的全部内容。
希望这可以帮助...
正如@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)
| 归档时间: |
|
| 查看次数: |
1128 次 |
| 最近记录: |