With this code
type Identity <T extends string> = T;
type MaybeString = string | undefined;
type StringOrNever = MaybeString extends undefined ? never : Identity<MaybeString>;
The compiler complain that undefined is not assignable to type String when using MaybeString as the Identity param.
Wondering if this is related to the distributive property of conditional types, i try that
type StringOrNever = [MaybeString] extends [undefined] ? [never] : Identity<MaybeString>;
which doesn't work either.
What am i doing wrong ?
CodePudding user response:
THis is not related to distributivity.
Distributive conditional types act on a generic type. MaybeString
in StringOrNever
is not generic.
MaybeString extends undefined
does not narrow it to string
. After this condition, MaybeString
still string | undefined
.
In order to make it work, you should parametrize StringOrNever
.
See this example:
type Identity<T extends string> = T;
type MaybeString = string | undefined;
type StringOrNever<T extends string | undefined> = T extends string ? Identity<T> : never
type Result1 = StringOrNever<'Hello'> // hello
type Result2 = StringOrNever<undefined> // never
type Result3 = StringOrNever<undefined | 'some stirng'> // 'some string'
There is an interesting case with Result3
. In fact, Result3
is a union of string and never: "some string" | never
. IN this case, never
is getting clashed with string
. SO, how do you want to handle union ? We can turn off distributivity, just like you did
type Identity<T extends string> = T;
type MaybeString = string | undefined;
type StringOrNever<T extends string | undefined> = [T] extends [string] ? Identity<T> : never
type Result1 = StringOrNever<'Hello'> // hello
type Result2 = StringOrNever<undefined> // never
type Result3 = StringOrNever<undefined | 'some stirng'> // never