Skip to content

Conditional type evaluation not deferred when it depends on an implicitly-present type parameter #59450

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
m-shaka opened this issue Jul 28, 2024 · 1 comment · Fixed by #59516
Closed
1 task done
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Milestone

Comments

@m-shaka
Copy link

m-shaka commented Jul 28, 2024

Acknowledgement

  • I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion.

Comment

I'm not sure if it's a bug, but it seems like it's inconsistency of generic type.

declare function f(fun: <T>(t: T) => void): void
f((t) => {
    type T = typeof t

    type IsAny = T extends any ? true: false // deferred
    type IsAnyArray = T[] extends any[] ? true: false // return true

    type IsString = T extends string ? true : false // deferred
    type IsStringArray = T[] extends string[] ? true : false // return false
})

function g<T>(t: T) {
    type IsAny = T extends any ? true: false // deferred
    type IsAnyArray = T[] extends any[] ? true: false // return true

    type IsString = T extends string ? true : false // deferred
    type IsStringArray = T[] extends string[] ? true : false // deferred
}

I expected IsStringArray is deferred in the function passed to f like the. body of g, but evaluated as false

TS version: 5.5.3
Reproduction code: playground

(First I raised a question on stackoverflow, but now I think this question is more suitable here https://stackoverflow.com/questions/78801369/strange-behavior-of-generic-types-in-typescript)

@RyanCavanaugh RyanCavanaugh added Not a Defect This behavior is one of several equally-correct options Bug A bug in TypeScript and removed Not a Defect This behavior is one of several equally-correct options labels Jul 29, 2024
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jul 29, 2024
@RyanCavanaugh RyanCavanaugh changed the title A strange behavior of generic type Conditional type evaluation not deferred when it depends on an implicitly-present type parameter Jul 29, 2024
@ahejlsberg
Copy link
Member

The issue here is that we fail to account for type parameters that are introduced through contextual typing, as happens in the arrow function in the example. The specific logic is in the getOuterTypeParameters function. I will put up a PR that fixes this.

Note that the issue also manifests in contextually typed function expressions and object literal methods, and in type references other than array types. For example:

const fun: <T>(x: T) => void = function test(t) {
    type IsObject = { x: typeof t } extends { x: string } ? true : false;  // Should be deferred, but isn't
};

const obj: { f: <T>(x: T) => void } = {
    f(t) {
        type IsObject = { x: typeof t } extends { x: string } ? true : false;  // Should be deferred, but isn't
    }
};

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