Typescript type alias let Intellisense show alias name, not source type
Asked Answered
M

2

5

Consider this short piece of code

type A = number;

declare function f(): A;

const a = f(); // `a` is number, not A

Why does TS show a: number instead of a: A?

Meltage answered 23/9, 2019 at 10:36 Comment(0)
D
3

Type aliases as their name suggests are just different names for another types. Type alias names are not something the compiler is guaranteed to preserve (unlike interfaces) and it applies a heuristic that gives the best user experience (in this case it arguably fails).

Also not that A and number are effectively the same type. If you want to ensure the un-assignablity of number to A you need to use branded types.

type A = number & { isA: undefined};

declare function f(): A;

const a = f(); // `a` is A, not number

play

Note: There are also a proposals (this and this) to have the branded type mechanism baked into typescript but at the time of writing it is not yet finalized.

Damnatory answered 23/9, 2019 at 11:55 Comment(0)
M
3

Here's how you can preserve the alias name, while using it like a number

interface PreserveAliasName extends Number {}
type A = number & PreserveAliasName;

declare function f(): A;
const a = f(); // `a` is A
const b: A = 5; // allows primitive assign, unlike branded types
const c = BigInt(b); // still allows usage like primitive

Compared to branded type:

type A = number & { __brand: 'A' };
declare function f(): A;
const a = f(); // `a` is A
const b: A = 5;
  Type 'number' is not assignable to type '{ __brand: "A"; }'
const b: A = 5 as A; // needs casting
const c = BigInt(b); // still allows usage like primitive

Compared to interface

interface A extends Number {}
declare function f(): A;
const a = f(); // `a` is A
const b: A = 5; // allows primitive assign
const c = BigInt(b)
  Argument of type 'A' is not assignable to parameter of type 'string | number | bigint | boolean'.
const c = BigInt(b as number) // needs casting
Mustee answered 5/8, 2022 at 15:58 Comment(1)
You can make __brand optional, i.e. { __brand?: 'A' } which wouldn't require casting.Lafontaine

© 2022 - 2024 — McMap. All rights reserved.