通用类型(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;

但是现在,你不知道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

【讨论】:

谢谢,我能理解的唯一解释。 :)【参考方案3】:

所有东西在运行时都是any,最重要的是它在JavaScript中的编译时是any。这就是为什么有 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

如果函数接受任何内容,您将在运行时遇到错误,这为时已晚。

【讨论】:

好。但是为什么我们需要使用 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)与打字稿中的任何类型有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

获取泛型函数的类型而不调用打字稿中的函数

打字稿中数组的两种写作有啥区别

打字稿中具有通用键的对象

通用无状态组件 React 的类型?或在打字稿中扩展通用函数接口以具有进一步的通用性?

无法让嵌套类型保护与打字稿中的联合类型一起使用

打字稿中的 *.d.ts 与 *.ts 有啥区别?