Skip to content

true extends false #28654

Closed
Closed
@AnyhowStep

Description

@AnyhowStep

TypeScript Version: 3.2.0-dev.20181117

EDIT: I just tested with TS 3.2.0-rc and it has this bug

Search Terms: true extends false

Code

I feel like I'm losing my mind here. Or maybe I'm tired because it's 3.34am. Maybe I need to take a break. Am I missing something obvious?

//OK
//Expected: "n"
//Actual: "n"
type no = true extends false ? "y" : "n";

type G<DataT extends { b : boolean }> = (
    true extends DataT["b"]?
    ["Actual", "true extends", DataT["b"]] :
    "Expected"
)

//Wat?
//Expected: "Expected"
//Actual: ["Actual", "true extends", false]
type g = G<{ b : false }>;

Expected behavior:

g to be of type "Expected".

Intuitively,

  1. DataT is of type { b : false }
  2. DataT["b"] is of type false
  3. true extends false should be... false

Actual behavior:

g is of type ["Actual", "true extends", false]

Playground Link: Here


EDIT: I just tested and this is not a problem in TS 3.0.1

I'm not crazy, phew.

Activity

AnyhowStep

AnyhowStep commented on Nov 23, 2018

@AnyhowStep
ContributorAuthor

This has no problems in either TS 3.2 or TS 3.0.1

type G<B extends boolean> = (
    true extends B?
    ["Actual", "true extends", B] :
    "Expected"
)

//OK
//Expected: "Expected"
//Actual: "Expected"
type g = G<false>;
jack-williams

jack-williams commented on Nov 23, 2018

@jack-williams
Collaborator

I think this is happening because of #27470

In G the constraint of DataT is being pulled down in the access expression DataT["b"]. So it is not that true extends false, rather it is eagerly using the base constraint in DataT so you get true extends boolean. This is not covered by the fix #27490 because "b" is not a generic type. You can see the correct behaviour if you defer the check using a parameter.

type G2<DataT extends { b : boolean }, B extends keyof DataT> = (
    true extends DataT[B]?
    ["Actual", "true extends", DataT[B]] :
    "Expected"
)
// g2: "Expected"
type g2 = G2<{ b: false }, "b">;

or even doing:

type G2<DataT extends { b : boolean }, B extends "b"> = (
    true extends DataT[B]?
    ["Actual", "true extends", DataT[B]] :
    "Expected"
)
// g2: "Expected"
type g2 = G2<{ b: false }, "b">;
AnyhowStep

AnyhowStep commented on Nov 23, 2018

@AnyhowStep
ContributorAuthor

Yikes. I hope this is fixed. This breaks a lot of my code that was working in 3.0.1.

Using your workaround would make the type declarations even more verbose and complex =(


Thank you for looking into it! I had this gnawing at me even as I tried to sleep.

I guess I'll hold off on upgrading TS for now :x

Jessidhia

Jessidhia commented on Nov 27, 2018

@Jessidhia

This might be related to some problems I found while working on the React types; proving that 'x' extends keyof T is not sufficient to let you index T with 'x'.

ahejlsberg

ahejlsberg commented on Nov 28, 2018

@ahejlsberg
Member

Simplified repro with expected outcomes:

type Foo<T extends { b: boolean }> = true extends T["b"] ? "yes" : "no";

type T0 = Foo<{ b: never }>     // "no"
type T1 = Foo<{ b: false }>;    // "no"
type T2 = Foo<{ b: true }>;     // "yes"
type T3 = Foo<{ b: boolean }>;  // "yes"

Currently Foo is eagerly evaluated to "yes" so every outcome is "yes".

AnyhowStep

AnyhowStep commented on Nov 29, 2018

@AnyhowStep
ContributorAuthor

Thank you for fixing this so quickly!

I just updated from 3.0.1 to 3.3.0-dev.20181129 and nothing broke!

2 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptDomain: Indexed Access TypesThe issue relates to accessing subtypes via index accessFixedA PR has been merged for this issue

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @Jessidhia@DanielRosenwasser@weswigham@ahejlsberg@jack-williams

      Issue actions

        true extends false · Issue #28654 · microsoft/TypeScript