通用类型(T)与打字稿中的任何类型有啥区别
Posted
技术标签:
【中文标题】通用类型(T)与打字稿中的任何类型有啥区别【英文标题】:What are the difference between generic Type(T) vs any in typescript通用类型(T)与打字稿中的任何类型有什么区别 【发布时间】:2017-10-16 19:26:59 【问题描述】:打字稿中generic Type(T)
与any
有什么区别?
功能1
function identity(arg: any): any
return arg;
功能2
function identity<T>(arg: T): T
return arg;
功能 3
function identity<T>(arg: T[]): T[]
return arg;
如果我们传递任何类型的
data type
,则函数 1 和 3 被接受,但如果我们传递array
,函数 2 不接受。 泛型类型在编译时接受所有类型的数据类型。但是这里为什么不接受呢?
还有哪个函数对性能更好(函数 1 或函数 3)?
【问题讨论】:
官网有很好的解释typescriptlang.org/docs/handbook/… @yurzui 那是很好的文件。这个怀疑只是从那里来的。谢谢。 【参考方案1】:如果这是一个只返回一个参数并且没有类型限制使用的标识函数,则没有区别:
const foo: any = fn(['whatever']);
而且键入的代码也有区别:
const foo: string = fn('ok');
const bar: string = fn([ not: 'ok' ]);
此外,泛型类型的使用提供了语义。此签名表明该函数是无类型的并返回任何内容:
function fn(arg: any): any ...
此签名表明该函数返回与其参数相同的类型:
function fn<T>(arg: T): T ...
实际函数通常比return arg
示例更有意义。泛型类型可以从类型限制中受益(而any
显然不能):
function fn<T>(arg: T[]): T[]
return arg.map((v, i) => arg[i - 1]);
但是当函数与其他泛型类和泛型函数结合使用时,好处会变得更加明显(如果涉及非泛型则消除):
function fn<T>(arg: T[]): T[]
return Array.from(new Set<T>(arg));
这允许在输入(参数)和输出(返回值)之间始终保持T
类型:
const foo: string[] = fn(['ok']);
const bar: string[] = fn([ not: 'ok' ]);
性能不会有任何差异,因为 TypeScript 类型仅在设计时存在。
【讨论】:
【参考方案2】:使用任何这些方法绝对没有性能差异,因为所有这些花哨的东西都只是Typescript
糖,仅用于开发。
所有类型检查仅在编译时进行(当 Typescript 在您的服务器中将您的代码转译/转换回普通 javascript 时)。
无论哪种方式,当您的代码发送到用户的浏览器时,它的外观是这样的:
function identity(arg)
return arg;
但要解释差异:
当使用 any
时,您将失去 Typescript 提供的所有类型检查和安全检查,而 T
的行为就像一个变量,它将保存您不知道的类型。
所以
function identity<T>(arg: T): T
return arg;
在上面,我们知道如果identify
接受number
,它将返回number
等等,其中:
function identity(arg: any): any
return arg;
但是现在,你不知道arg
和returned
的值是否相同。
T
将解决的另一个问题是,当您在类中创建一个方法时,它需要一个参数,您希望确保该方法只接受与类的构造函数参数类型相同的参数实例化时。
export class MyClass<T>
myMethod(anotherArg:T)
所以使用上面的:
let str = "string";
let instance = new MyClass(str);
instance.myMethod("other string") // will compile
在哪里:
let num = 32423423;
let instance = new MyClass(num);
instance.myMethod("other string") // won't compile
【讨论】:
谢谢,我能理解的唯一解释。 :)【参考方案3】:所有东西在运行时都是any
,最重要的是它在JavaScript
中的编译时是any
。这就是为什么有 TypeScript
在编译时提供类型安全的原因。
any
和 T
/ T extends
等之间的区别在于,例如,您在编译时具有类型安全性
protected typeSafety = <T extends String>(args:T):T =>
return args;
this.typeSafety(1); // compile error
this.typeSafety("string"); // good to go
如果函数接受任何内容,您将在运行时遇到错误,这为时已晚。
【讨论】:
好。但是为什么我们需要使用 T 的扩展呢?因为 T 接受C#
中的所有类型的数据类型。这就是它令人困惑的原因
@RameshRajendran 你已经定义了T
必须是什么。通常你会在一个由实现类扩展的泛型类中使用它。【参考方案4】:
T
的主要用途是避免在调用方法时破坏类型。
例子:
如果你这样做:
let foo = new Foo();
identity(foo).bar();
第二行对编译器来说没问题,但不是因为他知道bar
存在于Foo
类型中,因为它是any
,而any
可以有任何方法。
如果你这样做:
let foo = new Foo();
identity<Foo>(foo).bar();
identity<Foo>(foo).notExistingMethod();
第二行可以正常编译,而不是第三行,因为Foo
没有notExistingMethod
方法。
any 通常在您需要以更 Javascript 的方式创建某些东西时使用,这意味着您并不真正知道对象中有什么,因为 Javascript 没有任何类型(我不是在谈论 @ 987654330@ofc)。
【讨论】:
以上是关于通用类型(T)与打字稿中的任何类型有啥区别的主要内容,如果未能解决你的问题,请参考以下文章