generic Type(T)
et any
en tapuscrit?function identity(arg: any): any {
return arg;
}
function identity<T>(arg: T): T {
return arg;
}
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 unarray
. 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)?
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.
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
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).
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.