-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Constraints are not considered for Conditional Types #31096
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
Comments
This is working as intended. Conditional type resolution ignores type parameter constraints to prevent undesirable resolutions that violate transitivity. See this comment: // Return trueType for a definitely true extends check. We check instantiations of the two
// types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
// that has no constraint. This ensures that, for example, the type
// type Foo<T extends { x: any }> = T extends { x: string } ? string : number
// doesn't immediately resolve to 'string' instead of being deferred. A concrete example: function f<
TType extends { p: any },
>(
bla: TType
): TType["p"] extends string ? string : number {
return "test"; // If we used the constraint this would be legal.
}
const res: number = f({ p: 3 }); // res === "test"; There are cases where using the constraint is sound but it involves exploring the constraint type. |
I've managed to overcome this issue by replacing conditional types with map-types: function f<
TType extends { kind: "a" },
>(
bla: TType
): void {
const x: TType['kind'] = 'a'; // typechecks
let y: { a: string, b: number }[TType["kind"]]; // does not
y = "test";
y = 4;
} @jack-williams So this restriction is only because of any? |
In general the root of the issue is that assignability is not a transitive relation, however (Thanks to @rkirov for number four). I use
|
@jack-williams I ended up here looking for 'transitivity failures', so I got one more for you (no 'any's) declare let c: {a(): {}|null|void};
declare let b: {a(): void};
declare let a: {a(): unknown};
b = a;
c = b;
// but
c = a; // error Also that means it is not worth filing a bug, given the amount of other known failures. |
Since this seems to be as good a place as any to document transitivity failures and it's not listed yet, there's also some good ones with optional parameters. This one is fun because you can run it both directions. declare let x: (a?: number) => void;
declare let y: () => void;
declare let z: (a?: string) => void;
y = z;
x = y;
x = z; // error
y = x;
z = y;
z = x; // error |
TypeScript Version: 3.5.0-dev.20190424
Code
Expected behavior:
It typechecks.
Actual behavior:
It does not:
The assignment to
x
however typechecks.Playground Link
The text was updated successfully, but these errors were encountered: