4

In Python (typing) one can make a type alias (which is nothing more than a new name for a type) and a NewType, which is a type that is 100% the same as the underlying, but will be treated as unique by the type system. To quickly show the difference:

UserId = int   # Alias, meaning it's not considered a new type
def get_user(uid: UserId):
  # so this is the same as "def get_user(uid: int):"
  ...


get_user(3)  # and this is valid
UserId = typing.NewType("UserId", int)   # NewType, meaning it is considered a new type
def get_user(uid: UserId):
  # so this is NOT the same as "def get_user(uid: int):"
  ...


get_user(3)  # and this throws an error (in type checking)
get_user(UserId(3))  # (this works)
user_id = UserId(3)
get_user(user_id)  # as does this

Note that also in the case of NewType, at runtime the uid parameter is just an integer, and can be used in exactly that way.

In this trivial example the advantages of NewType are not so clear, but if you have a function with 5 parameters, some user_ids, some user_age, some department_id, etc, it's a life-saver if the type checker can alert you if you enter the parameters in the wrong order (and even better, if the IDE will just suggest the exact variable you need for each parameter, because it knows you have only one variable of type DepartmentId available!)

How to do the same in TypeScipt?

In TypeScript you can easily create type aliases:

type UserId = number

however, how to make something similar to NewType (where the typescript compiler will complain if you assign a simple number to a function that expects a UserId).

(Note that for custom objects, you could make a subclass; this question is mostly aimed at primitive objects (string, number, etc))

3
  • 3
    What you are describing is called "nominal types" and TypeScript does not support it. TypeScript is a structural type system. Commented Mar 12, 2022 at 14:31
  • 1
    That makes sense, I somehow this didn't "click" yet in my mind... Out of curiosity, do you think my workaround below is therefore an anti-pattern (or is maybe the whole idea of anti-patterns more pythonic than typescript-y) Commented Mar 16, 2022 at 9:17
  • 2
    That kind of impossible type assertion falls into a category that’s commonly called branding. (See this answer for a binary number example). Commented Mar 16, 2022 at 9:43

1 Answer 1

2

With a bit of typescript-hacking, you can make your own new types:

Define your new type as base type plus a fake field:

type UserId = number & {__my_hidden_type: "userId"}
type DepartmentId = number & {__my_hidden_type: "departmentId"}
// etc...

function getUser(uid: UserId) { }

getUserId(3)  // gives error
const notUserId = 3
getUserId(notUserId)  // gives error

getUserId(3 as UserId) // works

const userId = 3 as UserId
getUserId(userId) // works

For all intents and purposes, this does exactly what I would hope, except that the IDE thinks that there is a __my_hidden_type field on the uid variable; still, considering it's a hack, I would still be happy with a cleaner solution.

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

Comments

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.