2

Is any way to extend primitives like number to separate types of different classes?

type UserId = number;

class User {
  constructor(
    public id: UserId,
  ) {
      
  }
}

const usersIds: UserId[] = [];
const someUser = new User(1 as UserId);
usersIds.push(someUser.id); // <-- Correct
usersIds.push(2); // <-- Need to throw compile error

Playground

1 Answer 1

1

At runtime there wouldn't be a difference, but at compile time you can use a trick called branding to make the compiler think that UserId extends number:

type UserId = number & { __userId: true };

By intersecting number with an object type, we have defined a type which extends number but is not extended by number. Note that

const someUser = new User(1 as UserId);

is using a type assertion to lie to the compiler; 1 is not really a UserId according to that definition. And such lying is necessary because you don't really want to try to add a __userId property to a primitive number at runtime (you could mess with the Number prototype, but this would add such a property to every number, which defeats the purpose).

But it serves your needs:

usersIds.push(someUser.id); // okay
usersIds.push(2); // error!
// Argument of type 'number' is not assignable to parameter of type 'UserId'

Playground link to code

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! Branding is perfect for my case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.