Home > Back-end >  TypeScript type that is a string or number, or just number, but never just string
TypeScript type that is a string or number, or just number, but never just string

Time:09-15

I'm trying to make a type which can be either string | number or number but never just string. Here was my attempt, but as you can see, the string | number case just devolves into number. Is there any way to express this?

type StringOrNumberOrJustNumber<T extends string | number = string | number>
  = T extends number ? T : never;

// This becomes "number" but I'd like it to stay "string | number"
type StringOrNumber = StringOrNumberOrJustNumber<string | number>;

// This becomes "never" as desired, but an error would be even better
type JustString = StringOrNumberOrJustNumber<string>;

// This becomes "number" as desired
type JustNumber = StringOrNumberOrJustNumber<number>;

Playground Link

CodePudding user response:

You'll need another conditional, and you also have to wrap the types to be compared in [], making them tuples. This is because if you wrap them into tuples, they won't be naked types, and thus won't be distributed by the conditional.

Also notice that the second conditional, it's [string | number] extends [T] instead of the other way around. This is because you want to check if [string | number] is assignable to [T], not "is [T] assignable to [string | number], because both [string] and [number] are assignable to [string | number].

type StringOrNumberOrJustNumber<T extends string | number = string | number> = [T] extends [number] ? T : [string | number] extends [T] ? T : never;

Unfortunately I do not think it is possible to make it error when only a string is provided.

Anyways, here's the modified playground.

  • Related