Skip to content
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

Add missing conditional type relationships #24821

Closed

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Jun 9, 2018

Also:

  • Improve keyof reverse inference for non-string literal types (so an inference from 0 to keyof T produces a nonempty object for T).
  • Track substitution types for both true and false conditional branches, and for a greater variety of references (more than simply a bare reference or index - now substitutions for keyof, for example, would be allowed) This has two implications:
    • keyof T extends string ? keyof T : never now has the additional constraint on keyof T in the true branch correctly tracked.
    • keyof T extends string ? never : keyof T has the negation of its constraint in the false branch tracked (yes, that means conditional types now function as real negated types)

An example:

// @strict: true
function f1<T extends { foo: unknown; 0: unknown }>(_a: T, b: Extract<keyof T, string>) {
    b = "foo"; // succeeds
    b = 0; // errors
}

function f2<T extends { foo: unknown; 0: unknown }>(_a: T, b: Exclude<keyof T, string>) {
    b = "foo"; // errors
    b = 0; // succeeds
}

Note that the above are the critical usecases, since they're how we're telling people to workaround the keyof changes in 2.9 (hence the bundled keyof inference fix).

Fixes #24560

@ahejlsberg This is what I was talking about with you earlier. 590e4d5 has just the new relationships and the true-branch-only (as without the following two commits, the false branch would produce false positives) conditional-reverse inference checking implementation (less some bugfixes in the third commit), while 88623ad and aa2709f are about improving substitution types to be able to track the negation of a constraint in addition to the constraint itself, then enabling the false branch relation.

As an aside, I still don't create substitution types everywhere (though I certainly applied them to more locations) - generally, the usage of any generic type (or thing which can contain one) should potentially be a substitution type (which can then be removed by instantiation until it gets potentially reapplied later by relationship checking), so it can be matched on. Eg, { x: T } extends { x: string } ? { y: { x: T } } : never should be able to find { y: { x: (T & string) } } assignable to it when T extends number | string. This really brings home how substitution types are really just emulating flow control in the typespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong keyof behaviour for generic with extends types in 2.9
1 participant