-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Uniform Generics for Conditional Type Inference and Type Parameter Narrowing [Experiment] #30284
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
Conversation
Could you expand a bit on how the following example works with your implementation? function test1<T! extends number | boolean>(
b: T
): T {
if (typeof b === "boolean") {
// unsafe, since T could be false
return true;
}
return b;
} Does it reject this program? It should be rejected, since if it is accepted it results in unsoundness if const b = test1<false>(false);
// b === true while it has the type false |
The The callsite |
Yes, that makes sense. I was just curious to see how it worked.
Do you have an example in mind where it would be unsound? |
It depends on your definition of unsound - it's unlikely that code today would go observably wrong. The technical issue is that it violates parametricity, and various nice things you could learn from reading a type no longer apply. For instance. declare function swap<T extends true>(t: readonly [true, T]): readonly [T, true]; One assertion that holds today might be that function swap<T extends true>(t: readonly [true, T]): readonly [T, true] {
if (t[1] === true) {
return t; // as true <: T, and T <: true, therefore [true, T] <: [T, true]
}
return [t[1], t[0]];
} I also generates issues if you ever add name subtyping, where you could have a named subtype like flow. opaque type valid: true; // valid is a subtype of true, but true is not a subtype of valid The claim then that narrowing a generic |
This experiment is pretty old, so I'm going to close it to reduce the number of open PRs. |
This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise. |
This PR is an experimental implementation of uniform generics: Generic types that can only be instantiated with types that behave uniformly under
typeof
. This additional constraint makes it possible to apply new reasoning: something abit closer to dependent types.typeof
applies to all values of a uniform type. SeeequalityTransUniform
.fn
.The notation for uniform generic types is:
Type parameter
T
must be instantiated with a type that behaves uniformly undertypeof
, such asnumber
,boolean
,1 | 2 | 3
, but notnumber | boolean
,any
, orunknown
.This feature significantly benefits from #29317 and #29437.
The feature can also be extended to further uniformity constraints such as equality for enum members.
Examples (including ones from #22735 and #24929):