As I have seen, there is no native nameof
-keyword like C# has built into TypeScript . However, for the same reasons this exists in C#, I want to be able to refer to property names in a type safe manner.
This is especially useful in TypeScript when using jQuery plugins (Bootstrap-Tagsinput) or other libraries where the name of a property needs to be configured.
It could look like:
const name: string = nameof(Console.log);
// 'name' is now equal to "log"
The assignment of name
should change too when Console.log
got refactored and renamed.
What is the closest possible way of using such a feature in TypeScript as of now?
As you have already said, there is no built in functionality on TypeScript as of version 2.8. However, there are ways to get the same result:
ts-nameof is a library that provides the exact functionality as C# does (no longer recommended). With this you can do:
nameof(console); // => "console"
nameof(console.log); // => "log"
nameof<MyInterface>(); // => "MyInterface"
nameof<MyNamespace.MyInnerInterface>(); // => "MyInnerInterface"
ts-simple-nameof offers an alternative. It basically parses a stringified lambda to figure out the property name:
nameof<Comment>(c => c.user); // => "user"
nameof<Comment>(c => c.user.posts); // => "user.posts"
You can easily define your own nameof
that adds the type checking, however it will not refactor automatically as you'll still need to type a string literal:
const nameof = <T>(name: keyof T) => name;
It will return the passed property name but will generate a compile time error when the property name does not exist on type T
. Use it like so:
interface Person {
firstName: string;
lastName: string;
}
const personName1 = nameof<Person>("firstName"); // => "firstName"
const personName2 = nameof<Person>("noName"); // => compile time error
Credits and more information about this
The type keyof T
now not only resolves to a string, but to string | number | symbol
(ref). If you still want to resolve strings only, use this implementation instead:
const nameof = <T>(name: Extract<keyof T, string>): string => name;