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>;
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.