Search code examples
typescripttypes

nameof keyword in Typescript


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?


Solution

  • 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:

    Option 1: Using a library

    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"
    

    Option 2: Define a helper function

    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

    Update on helper function with TypeScript 2.9+

    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;