web-dev-qa-db-ja.com

ジェネリックType(T)とtypescriptのanyの違いは何ですか

Typescriptの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と3は、data type、しかし、arrayを渡す場合、関数2は受け入れません。 ジェネリック型はコンパイル時にすべての種類のデータ型を受け入れます。しかし、ここではなぜ受け入れないのですか?

また、どの関数がパフォーマンスの向上に適しているか(関数1または関数3)?

31

これが引数を返すだけのアイデンティティ関数であり、型制限なしで使用される場合、違いはありません。

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型は設計時にのみ存在するため、パフォーマンスに違いはありません。

23
Estus Flask

これらの派手なものはすべてTypeScript砂糖であり、開発専用であるため、これらのメソッドの使用中にパフォーマンスの違いはまったくありません。

すべての型チェックは、コンパイル時のみです(サーバーでTypeScriptがコードを通常のjavascriptに変換/変換する場合)。

いずれにしても、コードがユーザーのブラウザーに出荷されると、次のようになります。

function identity(arg){
    return arg;
}

しかし、違いを説明するには:

anyを使用すると、TypeScriptが提供するすべてのタイプチェックと安全性チェックが失われますが、Tは、何が起こっているかわからないタイプを保持する変数のように動作しますすることが。

そう

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

上記では、identifynumberを受け入れる場合、numberなどを返します。


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

しかし、今では、argreturnedの値が同じ型であるかどうかはわかりません。


Tが解決するもう1つの問題は、クラス内にメソッドを作成し、このメソッドがクラスのコンストラクターの引数と同じタイプの引数のみを受け入れるようにしたい引数を予期している場合です。インスタンス化されたとき。

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
15
Milad

Tの主な使用法は、メソッドを呼び出すときに型が壊れないようにすることです。

例:

もしあなたがそうするなら :

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

2行目はコンパイラにとっては問題ありませんが、barFoo型に存在し、anyであり、anyは任意の方法。

もしあなたがそうするなら :

let foo = new Foo();
identity<Foo>(foo).bar();
identity<Foo>(foo).notExistingMethod();

FooにはnotExistingMethodメソッドがないため、2行目は3行目ではなく正常にコンパイルされます。

anyは、より多くのJavascriptの方法で何かを作成する必要があるときによく使用されます。つまり、Javascriptには型がないため、オブジェクトの内容が実際にはわかりません(es6 ofc)。

3
Supamiu

すべてが実行時に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

関数が何かを受け入れた場合、実行時にエラーが発生し、手遅れになります。

2
Murat Karagöz