Hur man skapar en (python-liknande) NewType i TypeScript
I Python (typing) kan man göra ett type alias (vilket inte är något annat än ett nytt namn för en typ) och en NewType, som är en typ som är 100% densamma som den underliggande, men som kommer att behandlas som unik av typesystemet. För att snabbt visa skillnaden:
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
Observera att även i fallet med NewType är uid-parametern vid körning bara ett heltal, och kan användas på exakt det sättet.
I detta triviala exempel är fördelarna med NewType inte så tydliga, men om du har en funktion med 5 parametrar, några user_ids, några user_age, några department_id, osv, är det en livräddare om typkontrollen kan varna dig om du matar in parametrarna i fel ordning (och ännu bättre, om IDE:n bara föreslår exakt den variabel du behöver för varje parameter, eftersom den vet att du bara har en variabel av typen DepartmentId tillgänglig!)
Hur gör man samma sak i TypeScript?
I TypeScript kan du enkelt skapa typalias:
type UserId = number
men hur man gör något liknande NewType (där TypeScript-kompilatorn kommer att klaga om du tilldelar ett enkelt number till en funktion som förväntar sig ett UserId).
(Observera att för anpassade objekt kan du göra en underklass; den här frågan är mest riktad mot primitiva objekt (sträng, nummer, etc))
Svar #1
Med lite TypeScript-hackande kan du skapa dina egna nya typer:
Definiera din nya typ som baskodstyp plus ett falskt fält:
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
I praktiken gör detta exakt vad jag skulle hoppas, förutom att IDE:n tror att det finns ett __my_hidden_type-fält på uid-variabeln; fortfarande, med tanke på att det är en hack, skulle jag ändå vara nöjd med en renare lösning.
