泛型类型(T)与打字稿

时间:2017-05-17 11:04:39

标签: javascript angular typescript generics types

打字稿中的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;
}
  

功能1&amp;如果我们传递任何类型的data type,则接受3,但如果我们传递array,则函数2不接受。 泛型类型在编译时接受所有类型的数据类型。但这里为什么不接受?

哪个功能有利于提高性能(功能1或功能3)?

4 个答案:

答案 0 :(得分:22)

如果这是仅返回参数并且没有类型限制使用的标识函数,则没有区别:

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类型仅在设计时存在。

答案 1 :(得分:14)

使用任何这些方法时绝对没有性能差异,因为所有这些奇特的东西都只是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;
}

但现在,您还不知道argreturned值是否相同。

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

答案 2 :(得分:2)

运行时的所有内容都是any,而any在编译时它是JavaScript。这就是TypeScript在编译时提供类型安全的原因。

anyT / T extends等之间的区别在于您在编译期间具有类型安全性,例如

protected typeSafety = <T extends String>(args:T):T =>{
    return args;
}

this.typeSafety(1); // compile error
this.typeSafety("string"); // good to go

如果函数接受了任何内容,那么在运行时就会出现错误,为时已晚。

答案 3 :(得分:2)

T的主要用途是避免在调用方法时破坏类型。

示例:

如果你这样做:

let foo = new Foo();
identity(foo).bar();

第二行对于编译器是可以的,但不是因为他知道bar类型中存在Foo,因为它是any和{{1}可以有任何方法。

如果你这样做:

any

第二行将编译正常,而不是第三行,因为let foo = new Foo(); identity<Foo>(foo).bar(); identity<Foo>(foo).notExistingMethod(); 没有Foo方法。

当你需要以更多Javascript方式创建内容时,通常会使用任何内容,这意味着你并不真正知道对象中的内容,因为Javascript没有任何类型(I&#39 ;我不是在谈论notExistingMethod ofc)。