简体   繁体   English

TypeScript中泛型的行为

[英]Behavior of Generics in the TypeScript

I want to study TS a bit, and I am following the official page . 我想稍微学习一下TS,并且正在关注官方页面

I am on the Generics chapter 我在泛型章节

From the guide: 从指南:

function identity(arg: any): any {
    return arg;
}

They state the following: 他们声明如下:

While using any is certainly generic in that it will cause the function to accept any and all types for the type of arg, we actually are losing the information about what that type was when the function returns. 虽然使用any肯定是通用的,因为它将导致函数接受arg类型的任何类型和所有类型,但实际上,我们丢失了有关函数返回时该类型的信息 If we passed in a number, the only information we have is that any type could be returned. 如果我们传入一个数字,则唯一的信息就是可以返回任何类型。

Now lets observe this piece of code: 现在让我们观察这段代码:

let whatIsMyType = identity(666);
typeof whatIsMyType; // number

I have not lost type information. 我没有丢失类型信息。 What kind of loss they refer to? 他们指的是哪种损失?

Reading a bit further, guide suggests to use T type, as in: 进一步阅读,指南建议使用T型,如:

function identity<T>(arg: T): T {
    return arg;
}

With explanation: 附带说明:

We've now added a type variable T to the identity function. 现在,我们向身份函数添加了类型变量T。 This T allows us to capture the type the user provides (eg number), so that we can use that information later. 此T允许我们捕获用户提供的类型(例如,数字),以便我们以后可以使用该信息。 Here, we use T again as the return type. 在这里,我们再次使用T作为返回类型。 On inspection, we can now see the same type is used for the argument and the return type. 通过检查,我们现在可以看到参数和返回类型使用相同的类型。 This allows us to traffic that type information in one side of the function and out the other. 这使我们能够将键入信息的信息投放到函数的一侧,而另一端则从其中流出。

And lastly: function in TS (with any type of signature) 最后:TS中的功能(具有任何类型的签名)

function identity(arg: any): any {
    return arg;
}

and the function with generic type T: 以及具有通用类型T的函数:

function identity<T>(arg: T): T {
return arg;

} }

once compiled to plain JS, they look both identical: 一旦编译为普通的JS,它们看起来都是相同的:

function identity(arg) {
    return arg;
}

Now, I understand the benefit of early warning, I also understand the any signature. 现在,我了解了预警的好处,也了解了任何签名。 What I do not understand why saying I lost the type, and I should use "T" signature instead. 我不明白为什么说我丢失了类型,我应该使用“ T”签名代替。

Which is more complicated, and is basically identical. 这更复杂,并且基本上是相同的。

Now lets observe this piece of code: let whatIsMyType = identity(666); 现在让我们观察这段代码:let whatIsMyType = identity(666); typeof whatIsMyType; whatIsMyType的类型; // number I have not lost type information. //数字我还没有丢失类型信息。 What kind of loss they refer to? 他们指的是哪种损失?

It's about the difference between static type information and runtime type information. 它涉及静态类型信息和运行时类型信息之间的差异。 TypeScript is all about static type information — the information available to the TypeScript compiler to help you keep your program code correct. TypeScript都是关于静态类型信息的,TypeType编译器可以使用该信息来帮助您保持程序代码正确。 But typeof (in that context¹) is a runtime operation telling you what kind of value is stored in the variable whatIsMyType at runtime as of when you use typeof on it. 但是typeof (在这种情况下)是一种运行时操作,它告诉您在变量上使用typeof时在运行时变量whatIsMyType中存储了哪种值。

If you paste that code into the playground and hover your mouse over the whatIsMyType variable, you'll see that it has the type any , which means you can happily assign "foo" to it after the call to identity : 如果将代码粘贴到操场上,然后将鼠标悬停在whatIsMyType变量上,则会看到它的类型为any ,这意味着您可以在对identity的调用之后为它高兴地分配"foo"

function identity(arg: any): any {
    return arg;
}
let whatIsMyType = identity(666);
console.log(whatIsMyType);
whatIsMyType = "foo";          // No error here
console.log(whatIsMyType);

The variable is, for all intents and purposes, loosely typed like JavaScript variables are. 出于所有目的和目的,变量的类型类似于JavaScript变量。

TypeScript's goal, its raison d'être, is static type checking. TypeScript的目标是存在静态类型检查。 any is effectively an escape hatch for those situations (and they do exist, but are rare) where static type checking isn't useful (or even possible because of third-party integrations). 对于静态类型检查无用(或由于第三方集成而可能实现)的那些情况(确实存在,但很少见), any都有效。

once compiled to plain JS, they look both identical: 一旦编译为普通的JS,它们看起来都是相同的:

That's right. 那就对了。 The static type information that TypeScript uses is not part of the final output. TypeScript使用的静态类型信息不是最终输出的一部分。 It's a compile-time thing, not a runtime thing. 这是编译时的事情,而不是运行时的事情。 But notice how using the generic changes things — if you run this code in the playground : 但是请注意使用泛型是如何改变的—如果您在操场上运行以下代码:

function identity<T>(arg: T): T {
    return arg;
}
let whatIsMyType = identity(666);
console.log(whatIsMyType);
whatIsMyType = "foo";       // <== Error: Type '"foo"' is not assignable to type 'number'.
console.log(whatIsMyType);

...you can see that assigning "foo" to whatIsMyType is now a compile-time error. ...您可以看到,将whatIsMyType "foo"现在是编译时错误。


¹ ".. typeof (in that context)..." Somewhat confusingly, there is also a static typeof keyword in TypeScript that you can use where a type is expected, which is different from JavaScript's runtime typeof keyword (used in your example). ¹ “ .. typeof (在这种情况下...)...”有点令人困惑,您可以在TypeScript中使用静态的typeof关键字,该关键字可以在需要输入类型的地方使用,这与JavaScript的运行时typeof关键字(在您的示例中使用)不同。 In TypeScript, there are places a type is expected (a type context ), such as after the : in a variable declaration: 在TypeScript中,在变量声明中的某些位置,例如,在:之后有一个类型类型上下文 ):

let a: type_expected_here;

...and other places a value is expected (a value context ), such as the right-hand side of an assignment: ...以及其他需要值的地方( 值上下文 ),例如赋值的右侧:

a = value_expected_here;

If you use typeof in a type context , it's TypeScript's typeof operator. 如果在类型上下文中使用typeof ,则它是TypeScript的typeof运算符。 For instance, if you have this declaration: 例如,如果您有以下声明:

let foo: number = 42;

...you can use typeof bar to declare a variable whose type is the same as foo 's, like this : ...您可以使用typeof bar声明一个类型与foo相同的变量, 如下所示

let a: typeof foo;

Since that usage of typeof is where a type is expected, a will have the type number because that's foo 's type. 由于使用typeof是期望的类型 ,因此a将具有类型number因为那是foo的类型。 If you change foo 's declaration so it's a string instead, a 's type will change to follow suit. 如果你改变foo的声明,所以这是一个字符串,而不是, a的类型将改变跟风。

In contrast: 相反:

let a = typeof foo;

There, typeof is in a value context , so it's JavaScript's runtime typeof keyword, and a will get the value (not type) "number" (an in that specific example, a 's type will be inferred as string , since that's what JavaScript's typeof 's result always is). 那里, typeof值上下文中 ,因此它是JavaScript的运行时typeof关键字,并且a将获得值(而非类型) "number" (在该特定示例中, a 's的类型推断为string ,因为这就是JavaScript的含义) typeof的结果始终是)。

That seems very confusing at first, but gets clearer with time. 乍一看似乎很令人困惑,但随着时间的推移会变得更加清晰。

Sadly, TypeScript's typeof isn't well-described by the documentation. 可悲的是,文档中没有很好地描述TypeScript的typeof :-| :-|


Note that all of the above is from a TypeScript perspective. 请注意,以上所有内容都是从TypeScript角度来看的。 Whether you find static type checking a help or a hindrance is up to you. 是否找到静态类型检查帮助或障碍取决于您。 :-) But I'm assuming a TypeScript perspective for the purposes of this answer. :-)但是出于这个答案的目的,我假设使用TypeScript透视图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM