typescript 泛型类型(T)与任何类型脚本有什么区别

g2ieeal7  于 2023-01-14  发布在  TypeScript
关注(0)|答案(5)|浏览(155)

generic Type(T)any在 typescript 方面有何区别?

功能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)?

lp0sw83n

lp0sw83n1#

如果这是只返回一个参数的恒等函数,并且没有类型限制,则没有区别:

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

suzh9iv8

suzh9iv82#

使用这些方法时绝对没有性能差异,因为所有这些花哨的东西都只是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
cedebl8k

cedebl8k3#

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没有任何类型(我不是在谈论es6 ofc)。

h5qlskok

h5qlskok4#

所有的东西在运行时都是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

如果函数接受了任何东西,那么在运行时就会出现错误,这就太晚了。

cigdeys3

cigdeys35#

下面是一个简单的例子:

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

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

const name: string = 'karl';
const array: [] = [];

// Generic.

const genericName = generic(name);
const genericArray = generic(array);

console.info(parseInt(genericName));
console.info(parseInt(genericArray)); // Complains in TypeScript! (Argument of type '[]' is not assignable to parameter of type 'string'.ts(2345))

// Non generic.

const nonGenericName = nonGeneric(name);
const nonGenericArray = nonGeneric(array);

console.info(parseInt(nonGenericName));
console.info(parseInt(nonGenericArray)); // Does not complain in TypeScript!

正如我们所知,parseInt在传入数组时将无法正常工作。在非泛型示例中,您只有在运行代码时才会注意到这一点。在泛型示例中,TypeScript将提前提醒您(这是类型安全的全部要点!)

为什么一个抱怨,另一个不抱怨?

原因是泛型跟踪类型。这只适用于参数类型和返回类型相同的情况。否则就没有意义了。

何时应该使用泛型?

如果满足以下几点:

  • 如果函数接受多种类型。
  • 还返回输入值类型。

再举一个例子:

interface Obj<A, B> {
    type: A;
    value: B;
}

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

const objOne: Obj<string, Function> = {
    type: 'foo',
    value: (a) => a
};

const objTwo: Obj<number, boolean> = {
    type: 6,
    value: true
};

const objThree = {
    type: 'hello',
    value: 5
};

const genericObjOne = generic(objOne); // Hover over displays: "const genericObjOne: Obj<string, Function>"

const genericObjTwo = generic(objTwo); // Hover over displays: "const genericObjTwo: Obj<number, boolean>"

const genericObjThree = generic(objThree); // Hover over displays: "const genericObjThree: { type: string; value: number; }"

相关问题