Home > Mobile >  Typescript conditionnal type and branch narrowing
Typescript conditionnal type and branch narrowing

Time:05-16

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'

Playground

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
  • Related