Skip to content

Unexpected type evaluation with generic conditional typeΒ #52068

Description

@duanwilliam

Bug Report

πŸ”Ž Search Terms

generic types, deferred conditional types

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about Common "Bugs" That Aren't Bugs, Generics

⏯ Playground Link

Playground link with relevant code

or: a much more minimal example of the error, that does not appear in 4.9.4 but does appear in earlier playground versions

πŸ’» Code

type Or<A extends boolean, B extends boolean> = [A, B] extends [false, false] ? false : true
type And<A extends boolean, B extends boolean> = [A, B] extends [true, true] ? true : false
type Not<T extends boolean> = T extends true ? false : true
type Extends<A, B> = A extends B ? true : false

type IsStringLiteral<T> = false // type definition omitted and set to `false` (bug still appears)
type IsNumberLiteral<T> =
  And<
    Extends<T, number>,
    Not<Extends<number, T>>
  >

// !!!!!!!!!!!
type IsLiteral<T> = Or<IsStringLiteral<T>, IsNumberLiteral<T>>
//   ^?type IsLiteral<T> = true

or much more minimal example of error for playground versions <4.9:

type Or<A extends boolean, B extends boolean> = [A, B] extends [false, false] ? false : true

type IsString<T> = T extends string ? true : false

// ?????
type IsString2<T> = Or<IsString<T>, false>
//   ^?type IsString2<T> = false

// `Or` existing doesn't seem to be the problem
type IsString3<T> = [IsString<T>, false] extends [false, false] ? false : true
//   ^?type IsString3<T> = false

πŸ™ Actual behavior

The IsLiteral<T> type is always true, which is unexpected. I'd expect it to be computable only when type parameter T is passed in, as the value of T can change which branch of the conditional type to follow. For instance, expanding IsLiteral<T> for a given T, e.g. type IsStringTypeStringLiteral = Or<IsStringLiteral<string>, IsNumberLiteral<string>> gives the expected and "proper" result.

A comment from user xor_01 on the TS discord:

This is just my guess as to what's going on here:
instead of "calculate" actual type of IsNumberLiteral compiler decides for some reason to replace it with boolean and your implementation of Or returns true for boolean

πŸ™‚ Expected behavior

IsLiteral<T> shouldn't be replaced with true. Since the type parameter can affect the outcome of the conditional type, TS shouldn't determine the type to always follow some given condition.

Activity

  1. ahejlsberg commented on Jan 4, 2023

    @ahejlsberg
    Member

    We currently have logic to ensure conditional types of the form [X] extends [Y] ? A : B are deferred when X or Y are generic types. However, this logic only handles singleton tuples. We should extend it to handle tuples with multiple elements.

  2. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions