web-dev-qa-db-fra.com

Quelle est la différence entre le type générique (T) et tout type tapuscrit

Quelle est la différence entre generic Type(T) et any en tapuscrit?

Fonction 1

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

Fonction 2

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

Fonction 3

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

Les fonctions 1 et 3 sont acceptées si nous dépassons tout type de data type, Mais la fonction 2 n'accepte pas si on passe un array. le type générique accepte tous les types de données au moment de la compilation. mais ici pourquoi il n'accepte pas?

Quelle fonction est également bonne pour de meilleures performances (fonction 1 ou fonction 3)?

31
Ramesh Rajendran

Il n'y a aucune différence s'il s'agit d'une fonction d'identité qui renvoie simplement un argument et utilisée sans restrictions de type:

const foo: any = fn(['whatever']);

Et il y a une différence pour le code tapé:

const foo: string = fn('ok');
const bar: string = fn([{ not: 'ok' }]);

En outre, l'utilisation du type générique fournit une sémantique. Cette signature suggère que la fonction est non typée et renvoie n'importe quoi:

function fn(arg: any): any { ... }

Cette signature suggère que la fonction renvoie le même type que son argument:

function fn<T>(arg: T): T { ... }

Les fonctions réelles sont généralement plus significatives que simplement return arg exemple. Le type générique peut bénéficier de restrictions de type (tandis que any ne peut évidemment pas):

function fn<T>(arg: T[]): T[] {
  return arg.map((v, i) => arg[i - 1]);
}

Mais les avantages deviennent plus évidents lorsque la fonction est utilisée en conjonction avec d'autres classes génériques et fonctions génériques (et éliminée si des non génériques sont impliqués):

function fn<T>(arg: T[]): T[] {
  return Array.from(new Set<T>(arg));
}

Cela permet de maintenir de manière cohérente le type T entre l'entrée (argument) et la sortie (valeur retournée):

const foo: string[] = fn(['ok']);
const bar: string[] = fn([{ not: 'ok' }]);

Il ne peut y avoir aucune différence de performances car les types TypeScript n'existent qu'au moment de la conception.

23
Estus Flask

Il n'y a absolument aucune différence de performances lors de l'utilisation de l'une de ces méthodes, car toutes ces fantaisies ne sont que des sucres TypeScript et sont uniquement destinées au développement.

Toute la vérification de type se fait uniquement au moment de la compilation (lorsque TypeScript transpile/transforme votre code en javascript normal, sur votre serveur).

Quoi qu'il en soit, lorsque votre code est expédié au navigateur de l'utilisateur, voici à quoi il ressemble:

function identity(arg){
    return arg;
}

Mais pour expliquer les différences:

Lorsque vous utilisez any, vous perdrez toutes les vérifications de type et de sécurité que TypeScript propose, tandis que T se comporte comme une variable qui contiendra le type dont vous ne savez pas ce qu'il va faire. être.

Donc

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

Ci-dessus, nous savons que si identify accepte number, il renverra number et ainsi de suite, où:


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

Mais maintenant, vous ne savez pas si arg et la valeur returned sont du même type ou non.


L'autre problème que T résoudra est lorsque vous créez une méthode à l'intérieur d'une classe et qu'il attend un argument que vous voulez vous assurer que cette méthode n'acceptera que des arguments avec le même type que l'argument du constructeur de la classe une fois instancié.

export class MyClass<T>{

   myMethod(anotherArg:T){}

}

Donc, en utilisant ci-dessus:

let str = "string";
let instance = new MyClass(str);
instance.myMethod("other string") // will compile

Tandis que :

let num = 32423423;
let instance = new MyClass(num);
instance.myMethod("other string") // won't compile
15
Milad

L'utilisation principale de T est d'éviter de casser le type lorsque vous appelez une méthode.

Exemple:

Si tu fais :

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

La deuxième ligne sera correcte pour le compilateur, mais pas parce qu'il sait que bar existe dans le type Foo, car c'est any et any peut avoir n'importe quelle méthode.

Si tu fais :

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

La deuxième ligne se compilera correctement, pas la troisième car Foo n'a pas de méthode notExistingMethod.

any est souvent utilisé lorsque vous avez besoin de créer quelque chose d'une manière plus Javascript, ce qui signifie que vous ne savez pas vraiment ce qu'il y a dans votre objet, car Javascript n'a pas de types (je ne parle pas de es6 ofc).

3
Supamiu

Tout est any à l'exécution et en plus c'est any au moment de la compilation dans JavaScript. C'est pourquoi il existe TypeScript pour fournir une sécurité de type au moment de la compilation.

La différence entre any et T/T extends etc. est que vous avez une sécurité de type pendant la compilation par exemple

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

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

Si la fonction accepte quoi que ce soit, vous auriez l'erreur au moment de l'exécution qui serait trop tard.

2
Murat Karagöz