From 69e4dcf05156ef0a476108bdc2d62db55b675c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Thu, 19 Dec 2024 13:04:00 +0100 Subject: [PATCH] Improve assignability to target conditional types types that distribute with any/unknown `extendsType` --- src/compiler/checker.ts | 4 +- ...signabilityWithSimpleDistribution1.symbols | 71 +++++++++++++++++++ ...AssignabilityWithSimpleDistribution1.types | 64 +++++++++++++++++ ...signabilityWithSimpleDistribution2.symbols | 71 +++++++++++++++++++ ...AssignabilityWithSimpleDistribution2.types | 64 +++++++++++++++++ ...ypeAssignabilityWithSimpleDistribution1.ts | 22 ++++++ ...ypeAssignabilityWithSimpleDistribution2.ts | 22 ++++++ 7 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.symbols create mode 100644 tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.types create mode 100644 tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.symbols create mode 100644 tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.types create mode 100644 tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution1.ts create mode 100644 tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 34fd98bcbfe11..95b5294e0fb5d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19321,7 +19321,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isDistributionDependent(root: ConditionalRoot) { - return root.isDistributive && ( + return root.isDistributive && !(root.extendsType.flags & TypeFlags.AnyOrUnknown) && ( isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.trueType) || isTypeParameterPossiblyReferenced(root.checkType as TypeParameter, root.node.falseType) ); @@ -23206,7 +23206,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const c = target as ConditionalType; // We check for a relationship to a conditional type target only when the conditional type has no // 'infer' positions, is not distributive or is distributive but doesn't reference the check type - // parameter in either of the result types, and the source isn't an instantiation of the same + // parameter in either of the result types, and extends type is other than unknown or any, and the source isn't an instantiation of the same // conditional type (as happens when computing variance). if (!c.root.inferTypeParameters && !isDistributionDependent(c.root) && !(source.flags & TypeFlags.Conditional && (source as ConditionalType).root === c.root)) { // Check if the conditional is always true or always false but still deferred for distribution purposes. diff --git a/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.symbols b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.symbols new file mode 100644 index 0000000000000..0fdf9fd77b47f --- /dev/null +++ b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.symbols @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution1.ts] //// + +=== conditionalTypeAssignabilityWithSimpleDistribution1.ts === +type AllKeys = T extends unknown ? keyof T : never; +>AllKeys : Symbol(AllKeys, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 13)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 13)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 13)) + +type WithKeyOfConstraint = unknown; +>WithKeyOfConstraint : Symbol(WithKeyOfConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 54)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 2, 25)) +>K : Symbol(K, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 2, 27)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 2, 25)) + +type Test1 = WithKeyOfConstraint>; // ok +>Test1 : Symbol(Test1, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 2, 57)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 3, 11)) +>WithKeyOfConstraint : Symbol(WithKeyOfConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 54)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 3, 11)) +>AllKeys : Symbol(AllKeys, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 3, 11)) + +type WithAllKeysConstraint> = unknown; +>WithAllKeysConstraint : Symbol(WithAllKeysConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 3, 51)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 5, 27)) +>K : Symbol(K, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 5, 29)) +>AllKeys : Symbol(AllKeys, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 5, 27)) + +type Test2 = WithAllKeysConstraint; // ok +>Test2 : Symbol(Test2, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 5, 62)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 6, 11)) +>WithAllKeysConstraint : Symbol(WithAllKeysConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 3, 51)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 6, 11)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 6, 11)) + +declare function test3( +>test3 : Symbol(test3, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 6, 50)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 8, 23)) + + p1: T, +>p1 : Symbol(p1, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 8, 26)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 8, 23)) + + p2: T extends unknown ? T & { css?: unknown } : never, +>p2 : Symbol(p2, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 9, 8)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 8, 23)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 8, 23)) +>css : Symbol(css, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 10, 31)) + +): void; + +const wrapper =

(props: P) => { +>wrapper : Symbol(wrapper, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 13, 5)) +>P : Symbol(P, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 13, 17)) +>props : Symbol(props, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 13, 35)) +>P : Symbol(P, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 13, 17)) + + test3( +>test3 : Symbol(test3, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 6, 50)) + + props, +>props : Symbol(props, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 13, 35)) + + props, // ok +>props : Symbol(props, Decl(conditionalTypeAssignabilityWithSimpleDistribution1.ts, 13, 35)) + + ); +}; + diff --git a/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.types b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.types new file mode 100644 index 0000000000000..8eb0fdfb1eb81 --- /dev/null +++ b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution1.types @@ -0,0 +1,64 @@ +//// [tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution1.ts] //// + +=== conditionalTypeAssignabilityWithSimpleDistribution1.ts === +type AllKeys = T extends unknown ? keyof T : never; +>AllKeys : AllKeys +> : ^^^^^^^^^^ + +type WithKeyOfConstraint = unknown; +>WithKeyOfConstraint : unknown +> : ^^^^^^^ + +type Test1 = WithKeyOfConstraint>; // ok +>Test1 : unknown +> : ^^^^^^^ + +type WithAllKeysConstraint> = unknown; +>WithAllKeysConstraint : unknown +> : ^^^^^^^ + +type Test2 = WithAllKeysConstraint; // ok +>Test2 : unknown +> : ^^^^^^^ + +declare function test3( +>test3 : (p1: T, p2: T extends unknown ? T & { css?: unknown; } : never) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + + p1: T, +>p1 : T +> : ^ + + p2: T extends unknown ? T & { css?: unknown } : never, +>p2 : T extends unknown ? T & { css?: unknown; } : never +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ +>css : unknown +> : ^^^^^^^ + +): void; + +const wrapper =

(props: P) => { +>wrapper :

(props: P) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^ +>

(props: P) => { test3( props, props, // ok );} :

(props: P) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^ +>props : P +> : ^ + + test3( +>test3( props, props, // ok ) : void +> : ^^^^ +>test3 : (p1: T, p2: T extends unknown ? T & { css?: unknown; } : never) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + + props, +>props : P +> : ^ + + props, // ok +>props : P +> : ^ + + ); +}; + diff --git a/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.symbols b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.symbols new file mode 100644 index 0000000000000..18dab67fd26fd --- /dev/null +++ b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.symbols @@ -0,0 +1,71 @@ +//// [tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution2.ts] //// + +=== conditionalTypeAssignabilityWithSimpleDistribution2.ts === +type AllKeys = T extends any ? keyof T : never; +>AllKeys : Symbol(AllKeys, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 13)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 13)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 13)) + +type WithKeyOfConstraint = unknown; +>WithKeyOfConstraint : Symbol(WithKeyOfConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 50)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 2, 25)) +>K : Symbol(K, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 2, 27)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 2, 25)) + +type Test1 = WithKeyOfConstraint>; // ok +>Test1 : Symbol(Test1, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 2, 57)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 3, 11)) +>WithKeyOfConstraint : Symbol(WithKeyOfConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 50)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 3, 11)) +>AllKeys : Symbol(AllKeys, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 3, 11)) + +type WithAllKeysConstraint> = unknown; +>WithAllKeysConstraint : Symbol(WithAllKeysConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 3, 51)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 5, 27)) +>K : Symbol(K, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 5, 29)) +>AllKeys : Symbol(AllKeys, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 0, 0)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 5, 27)) + +type Test2 = WithAllKeysConstraint; // ok +>Test2 : Symbol(Test2, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 5, 62)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 6, 11)) +>WithAllKeysConstraint : Symbol(WithAllKeysConstraint, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 3, 51)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 6, 11)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 6, 11)) + +declare function test3( +>test3 : Symbol(test3, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 6, 50)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 8, 23)) + + p1: T, +>p1 : Symbol(p1, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 8, 26)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 8, 23)) + + p2: T extends any ? T & { css?: unknown } : never, +>p2 : Symbol(p2, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 9, 8)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 8, 23)) +>T : Symbol(T, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 8, 23)) +>css : Symbol(css, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 10, 27)) + +): void; + +const wrapper =

(props: P) => { +>wrapper : Symbol(wrapper, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 13, 5)) +>P : Symbol(P, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 13, 17)) +>props : Symbol(props, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 13, 35)) +>P : Symbol(P, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 13, 17)) + + test3( +>test3 : Symbol(test3, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 6, 50)) + + props, +>props : Symbol(props, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 13, 35)) + + props, // ok +>props : Symbol(props, Decl(conditionalTypeAssignabilityWithSimpleDistribution2.ts, 13, 35)) + + ); +}; + diff --git a/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.types b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.types new file mode 100644 index 0000000000000..4f532b1b89c4b --- /dev/null +++ b/tests/baselines/reference/conditionalTypeAssignabilityWithSimpleDistribution2.types @@ -0,0 +1,64 @@ +//// [tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution2.ts] //// + +=== conditionalTypeAssignabilityWithSimpleDistribution2.ts === +type AllKeys = T extends any ? keyof T : never; +>AllKeys : AllKeys +> : ^^^^^^^^^^ + +type WithKeyOfConstraint = unknown; +>WithKeyOfConstraint : unknown +> : ^^^^^^^ + +type Test1 = WithKeyOfConstraint>; // ok +>Test1 : unknown +> : ^^^^^^^ + +type WithAllKeysConstraint> = unknown; +>WithAllKeysConstraint : unknown +> : ^^^^^^^ + +type Test2 = WithAllKeysConstraint; // ok +>Test2 : unknown +> : ^^^^^^^ + +declare function test3( +>test3 : (p1: T, p2: T extends any ? T & { css?: unknown; } : never) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + + p1: T, +>p1 : T +> : ^ + + p2: T extends any ? T & { css?: unknown } : never, +>p2 : T extends any ? T & { css?: unknown; } : never +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ +>css : unknown +> : ^^^^^^^ + +): void; + +const wrapper =

(props: P) => { +>wrapper :

(props: P) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^ +>

(props: P) => { test3( props, props, // ok );} :

(props: P) => void +> : ^ ^^^^^^^^^ ^^ ^^ ^^^^^^^^^ +>props : P +> : ^ + + test3( +>test3( props, props, // ok ) : void +> : ^^^^ +>test3 : (p1: T, p2: T extends any ? T & { css?: unknown; } : never) => void +> : ^ ^^ ^^ ^^ ^^ ^^^^^ + + props, +>props : P +> : ^ + + props, // ok +>props : P +> : ^ + + ); +}; + diff --git a/tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution1.ts b/tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution1.ts new file mode 100644 index 0000000000000..87438fa4311ee --- /dev/null +++ b/tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution1.ts @@ -0,0 +1,22 @@ +// @strict: true +// @noEmit: true + +type AllKeys = T extends unknown ? keyof T : never; + +type WithKeyOfConstraint = unknown; +type Test1 = WithKeyOfConstraint>; // ok + +type WithAllKeysConstraint> = unknown; +type Test2 = WithAllKeysConstraint; // ok + +declare function test3( + p1: T, + p2: T extends unknown ? T & { css?: unknown } : never, +): void; + +const wrapper =

(props: P) => { + test3( + props, + props, // ok + ); +}; diff --git a/tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution2.ts b/tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution2.ts new file mode 100644 index 0000000000000..22d650c95a682 --- /dev/null +++ b/tests/cases/compiler/conditionalTypeAssignabilityWithSimpleDistribution2.ts @@ -0,0 +1,22 @@ +// @strict: true +// @noEmit: true + +type AllKeys = T extends any ? keyof T : never; + +type WithKeyOfConstraint = unknown; +type Test1 = WithKeyOfConstraint>; // ok + +type WithAllKeysConstraint> = unknown; +type Test2 = WithAllKeysConstraint; // ok + +declare function test3( + p1: T, + p2: T extends any ? T & { css?: unknown } : never, +): void; + +const wrapper =

(props: P) => { + test3( + props, + props, // ok + ); +};