Type-safe strings in TypeScript

Posted on 2019-11-27

If you're working with lots of different IDs it's easy to mix them up in function calls:

function getUserInfo(customerId: string, userId: string): UserInfo {
    // just an example
}

With this function the compiler would not know if you put the userId in customerId and vice versa.

Typescript to the rescue

interface CustomerId extends String {
    __customer_id: never;
}

interface UserId extends String {
    __user_id: never;
}

function getUserInfo(customerId: CustomerId, userId: UserId): UserInfo {
    // just an example
}

With this in place the compiler will tell you if you have mixed up the parameter order.

Also, there is no runtime overhead, as these types will be removed by the transpilation process.

If you need to create an ID in code, you still need these utility functions:

const asCustomerId = (id: string): CustomerId => id as unknown as CustomerId;
const asUserId = (id: string): UserId => id as unknown as UserId;

getUserById(asCustomerId("my-customer-id"), asUserId("my-user-id"));
getUserById(asUserId("my-user-id"), asCustomerId("my-customer-id")); // compiler error