Home > Mobile >  Detecting type literals works in isolation but not when combined with other literal types
Detecting type literals works in isolation but not when combined with other literal types

Time:10-27

I have a series of type utilities which test whether a given type <T> is the literal or wide variant of the type:

  • IsStringLiteral<T extends string>
  • IsNumericLiteral<T extends number>
  • IsBooleanLiteral<T extends boolean>

I then wanted to wrap these utilities into a single utility IsLiteral which looks like the following:

export type IsLiteral<T extends string | number | boolean> = T extends string
  ? IsStringLiteral<T>
  : T extends boolean
    ? IsBooleanLiteral<T>
    : T extends number
      ? IsNumericLiteral<T>
      : never;

I am running type tests on all of the individual utilities as well as my master blaster IsLiteral and everything works ... except I get a false positive for booleans when I test IsLiteral<boolean> and yet IsBooleanLiteral<boolean> works as expected.

You can find info on the IsLiteral here: [ enter image description here

CodePudding user response:

This is because boolean is internally represented as true | false. That means it'll be distributed in this conditional:

  : T extends boolean
    ? IsBooleanLiteral<T>

and it'll now be:

(true extends boolean ? IsBooleanLiteral<true> : ...) | (false extends boolean ? IsBooleanLiteral<false> : ...)

which simplifies to:

IsBooleanLiteral<true> | IsBooleanLiteral<false>

both of which are true, so you get true for boolean. You can avoid this by wrapping it in a tuple. This is described in distributive conditional types in the handbook:

  : [T] extends [boolean]
    ? IsBooleanLiteral<T>

Playground

  • Related