Comme je l'ai vu, il n'y a pas de nameof
- mot-clé natif comme C # a intégré à TypeScript. Cependant, pour les mêmes raisons que cela existe en C #, je souhaite pouvoir faire référence aux noms de propriété de manière sécurisée.
Ceci est particulièrement utile dans TypeScript lorsque vous utilisez des plugins jQuery ( Bootstrap-Tagsinput ) ou d'autres bibliothèques dans lesquelles le nom d'une propriété doit être configuré.
Cela pourrait ressembler à:
const name: string = nameof(Console.log);
// 'name' is now equal to "log"
L'affectation de name
devrait également changer lorsque Console.log
a été refactorisé et renommé.
Quelle est la meilleure façon possible d'utiliser une telle fonctionnalité dans TypeScript dès maintenant?
Comme vous l'avez déjà dit, il n'y a pas de fonctionnalité intégrée sur TypeScript à partir de la version 2.8. Cependant, il existe des moyens d'obtenir le même résultat:
ts-nameof est une bibliothèque qui fournit la même fonctionnalité que C #. Avec cela, vous pouvez faire:
nameof(console); // => "console"
nameof(console.log); // => "log"
nameof<MyInterface>(); // => "MyInterface"
nameof<MyNamespace.MyInnerInterface>(); // => "MyInnerInterface"
Vous pouvez facilement définir votre propre nameof
qui ajoute la vérification de type, mais cela ne se refactorisera pas automatiquement car vous devrez toujours taper un littéral de chaîne:
const nameof = <T>(name: keyof T) => name;
Il renverra le nom de propriété passé mais générera une erreur de compilation lorsque le nom de propriété n'existe pas sur le type T
. Utilisez-le comme suit:
interface Person {
firstName: string;
lastName: string;
}
const personName1 = nameof<Person>("firstName"); // => "firstName"
const personName2 = nameof<Person>("noName"); // => compile time error
Crédits et plus d'informations à ce sujet
Le type keyof T
résout maintenant non seulement en une chaîne, mais en string | number | symbol
_ ( ref ). Si vous souhaitez toujours résoudre les chaînes uniquement, utilisez plutôt cette implémentation:
const nameof = <T>(name: Extract<keyof T, string>): string => name;
Je pense que nous avons souvent besoin de plus: pour obtenir les noms de propriété de classe au moment de l'exécution avec la validation à la compilation. C'est une fonctionnalité vraiment utile:
export type valueOf<T> = T[keyof T];
export function nameOf<T, V extends T[keyof T]>(f: (x: T) => V): valueOf<{ [K in keyof T]: T[K] extends V ? K : never }>;
export function nameOf(f: (x: any) => any): keyof any {
var p = new Proxy({}, {
get: (target, key) => key
})
return f(p);
}
Exemple d'utilisation (sans chaînes!):
if (update.key !== nameOf((_: SomeClass) => _.someProperty)) {
// ...
}