diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 75be36474222f..5148b1d306c77 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -26802,13 +26802,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (candidate === blockedStringType) { return; } - if (inference.priority === undefined || priority < inference.priority) { + const combinedPriority = priority | (inference.individualPriority || InferencePriority.None); + if (inference.priority === undefined || priority < (inference.priority & ~InferencePriority.DistributiveConditional)) { inference.candidates = undefined; inference.contraCandidates = undefined; inference.topLevel = true; - inference.priority = priority; + inference.priority = combinedPriority; } - if (priority === inference.priority) { + if (priority === (inference.priority & ~InferencePriority.DistributiveConditional)) { + // "upgrade" the priority (by essentially removing DistributiveConditional bit) of the inference without discarding the collected candidates + if (inference.priority > combinedPriority) { + inference.priority = combinedPriority; + clearCachedInferences(inferences); + } // We make contravariant inferences only if we are in a pure contravariant position, // i.e. only if we have not descended into a bivariant position. if (contravariant && !bivariant) { @@ -27174,6 +27180,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function inferToConditionalType(source: Type, target: ConditionalType) { + const info = target.root.isDistributive ? getInferenceInfoForType(getActualTypeVariable(target.checkType)) : undefined; + const saveIndividualPriority = info?.individualPriority; + if (info) { + info.individualPriority = (info.individualPriority || InferencePriority.None) | InferencePriority.DistributiveConditional; + } if (source.flags & TypeFlags.Conditional) { inferFromTypes((source as ConditionalType).checkType, target.checkType); inferFromTypes((source as ConditionalType).extendsType, target.extendsType); @@ -27184,6 +27195,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0); } + if (info) { + info.individualPriority = saveIndividualPriority; + } } function inferToTemplateLiteralType(source: Type, target: TemplateLiteralType) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1cfe3e04ba68d..5b0607f38b7be 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -7102,11 +7102,12 @@ export const enum InferencePriority { ContravariantConditional = 1 << 6, // Conditional type in contravariant position ReturnType = 1 << 7, // Inference made from return type of generic function LiteralKeyof = 1 << 8, // Inference made from a string literal to a keyof T - NoConstraints = 1 << 9, // Don't infer from constraints of instantiable types - AlwaysStrict = 1 << 10, // Always use strict rules for contravariant inferences - MaxValue = 1 << 11, // Seed for inference priority tracking + DistributiveConditional = 1 << 9, + NoConstraints = 1 << 10, // Don't infer from constraints of instantiable types + AlwaysStrict = 1 << 11, // Always use strict rules for contravariant inferences + MaxValue = 1 << 12, // Seed for inference priority tracking - PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates + PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof | DistributiveConditional, // These priorities imply that the resulting type should be a combination of all candidates Circularity = -1, // Inference circularity (value less than all other priorities) } @@ -7118,6 +7119,7 @@ export interface InferenceInfo { contraCandidates: Type[] | undefined; // Candidates in contravariant positions (or undefined) inferredType?: Type; // Cache for resolved inferred type priority?: InferencePriority; // Priority of current inference set + individualPriority?: InferencePriority; topLevel: boolean; // True if all inferences are to top level occurrences isFixed: boolean; // True if inferences are fixed impliedArity?: number; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 943ff5e152290..b1f8e59d05884 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -6893,10 +6893,11 @@ declare namespace ts { ContravariantConditional = 64, ReturnType = 128, LiteralKeyof = 256, - NoConstraints = 512, - AlwaysStrict = 1024, - MaxValue = 2048, - PriorityImpliesCombination = 416, + DistributiveConditional = 512, + NoConstraints = 1024, + AlwaysStrict = 2048, + MaxValue = 4096, + PriorityImpliesCombination = 928, Circularity = -1, } interface FileExtensionInfo { diff --git a/tests/baselines/reference/genericFunctionParametersConditionalType1.symbols b/tests/baselines/reference/genericFunctionParametersConditionalType1.symbols new file mode 100644 index 0000000000000..f89e37c677e74 --- /dev/null +++ b/tests/baselines/reference/genericFunctionParametersConditionalType1.symbols @@ -0,0 +1,145 @@ +//// [tests/cases/compiler/genericFunctionParametersConditionalType1.ts] //// + +=== genericFunctionParametersConditionalType1.ts === +// https://github.com/microsoft/TypeScript/issues/62079 + +export {}; + +interface _Map { +>_Map : Symbol(_Map, Decl(genericFunctionParametersConditionalType1.ts, 2, 10)) + + foo: { a: 123 } +>foo : Symbol(_Map.foo, Decl(genericFunctionParametersConditionalType1.ts, 4, 16)) +>a : Symbol(a, Decl(genericFunctionParametersConditionalType1.ts, 5, 8)) +} + +type ModuleSubType = "bar" & { brand: true }; +>ModuleSubType : Symbol(ModuleSubType, Decl(genericFunctionParametersConditionalType1.ts, 6, 1)) +>brand : Symbol(brand, Decl(genericFunctionParametersConditionalType1.ts, 8, 30)) + +type Map = _Map & Record +>Map : Symbol(Map, Decl(genericFunctionParametersConditionalType1.ts, 8, 45)) +>_Map : Symbol(_Map, Decl(genericFunctionParametersConditionalType1.ts, 2, 10)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>ModuleSubType : Symbol(ModuleSubType, Decl(genericFunctionParametersConditionalType1.ts, 6, 1)) +>blah : Symbol(blah, Decl(genericFunctionParametersConditionalType1.ts, 10, 41)) + +type SubTypeGet< +>SubTypeGet : Symbol(SubTypeGet, Decl(genericFunctionParametersConditionalType1.ts, 10, 57)) + + SubType extends string, +>SubType : Symbol(SubType, Decl(genericFunctionParametersConditionalType1.ts, 12, 16)) + + Map extends Record, +>Map : Symbol(Map, Decl(genericFunctionParametersConditionalType1.ts, 13, 25)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>SubType : Symbol(SubType, Decl(genericFunctionParametersConditionalType1.ts, 12, 16)) + +> = SubType extends unknown +>SubType : Symbol(SubType, Decl(genericFunctionParametersConditionalType1.ts, 12, 16)) + +? { type?: SubType } & Map[SubType] +>type : Symbol(type, Decl(genericFunctionParametersConditionalType1.ts, 16, 3)) +>SubType : Symbol(SubType, Decl(genericFunctionParametersConditionalType1.ts, 12, 16)) +>Map : Symbol(Map, Decl(genericFunctionParametersConditionalType1.ts, 13, 25)) +>SubType : Symbol(SubType, Decl(genericFunctionParametersConditionalType1.ts, 12, 16)) + +: never; + +type TestParameters = Parameters<(arg: SubTypeGet) => void> +>TestParameters : Symbol(TestParameters, Decl(genericFunctionParametersConditionalType1.ts, 17, 8)) +>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 19, 34)) +>ModuleSubType : Symbol(ModuleSubType, Decl(genericFunctionParametersConditionalType1.ts, 6, 1)) +>arg : Symbol(arg, Decl(genericFunctionParametersConditionalType1.ts, 19, 67)) +>SubTypeGet : Symbol(SubTypeGet, Decl(genericFunctionParametersConditionalType1.ts, 10, 57)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 19, 34)) +>Map : Symbol(Map, Decl(genericFunctionParametersConditionalType1.ts, 8, 45)) + +declare class Test { +>Test : Symbol(Test, Decl(genericFunctionParametersConditionalType1.ts, 19, 100)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 21, 19)) +>ModuleSubType : Symbol(ModuleSubType, Decl(genericFunctionParametersConditionalType1.ts, 6, 1)) + + constructor(arg: SubTypeGet); +>arg : Symbol(arg, Decl(genericFunctionParametersConditionalType1.ts, 22, 14)) +>SubTypeGet : Symbol(SubTypeGet, Decl(genericFunctionParametersConditionalType1.ts, 10, 57)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 21, 19)) +>Map : Symbol(Map, Decl(genericFunctionParametersConditionalType1.ts, 8, 45)) +} + +type TestConstructorParameters = ConstructorParameters; +>TestConstructorParameters : Symbol(TestConstructorParameters, Decl(genericFunctionParametersConditionalType1.ts, 23, 1)) +>ConstructorParameters : Symbol(ConstructorParameters, Decl(lib.es5.d.ts, --, --)) +>Test : Symbol(Test, Decl(genericFunctionParametersConditionalType1.ts, 19, 100)) + +declare class Animal { eat(): void; } +>Animal : Symbol(Animal, Decl(genericFunctionParametersConditionalType1.ts, 25, 68)) +>eat : Symbol(Animal.eat, Decl(genericFunctionParametersConditionalType1.ts, 27, 22)) + +declare class Cat extends Animal { meow(): void; } +>Cat : Symbol(Cat, Decl(genericFunctionParametersConditionalType1.ts, 27, 37)) +>Animal : Symbol(Animal, Decl(genericFunctionParametersConditionalType1.ts, 25, 68)) +>meow : Symbol(Cat.meow, Decl(genericFunctionParametersConditionalType1.ts, 28, 34)) + +declare class Dog extends Animal { bark(): void; } +>Dog : Symbol(Dog, Decl(genericFunctionParametersConditionalType1.ts, 28, 50)) +>Animal : Symbol(Animal, Decl(genericFunctionParametersConditionalType1.ts, 25, 68)) +>bark : Symbol(Dog.bark, Decl(genericFunctionParametersConditionalType1.ts, 29, 34)) + +type WithDistributiveConditionalDirectlyInParam = ( +>WithDistributiveConditionalDirectlyInParam : Symbol(WithDistributiveConditionalDirectlyInParam, Decl(genericFunctionParametersConditionalType1.ts, 29, 50)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 31, 51)) +>Cat : Symbol(Cat, Decl(genericFunctionParametersConditionalType1.ts, 27, 37)) +>Dog : Symbol(Dog, Decl(genericFunctionParametersConditionalType1.ts, 28, 50)) + + arg: T extends unknown ? T : never, +>arg : Symbol(arg, Decl(genericFunctionParametersConditionalType1.ts, 31, 72)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 31, 51)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 31, 51)) + +) => void; + +type Result1 = Parameters; +>Result1 : Symbol(Result1, Decl(genericFunctionParametersConditionalType1.ts, 33, 10)) +>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --)) +>WithDistributiveConditionalDirectlyInParam : Symbol(WithDistributiveConditionalDirectlyInParam, Decl(genericFunctionParametersConditionalType1.ts, 29, 50)) + +type WithDistributiveConditionalNested = ( +>WithDistributiveConditionalNested : Symbol(WithDistributiveConditionalNested, Decl(genericFunctionParametersConditionalType1.ts, 35, 70)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 37, 42)) +>Cat : Symbol(Cat, Decl(genericFunctionParametersConditionalType1.ts, 27, 37)) +>Dog : Symbol(Dog, Decl(genericFunctionParametersConditionalType1.ts, 28, 50)) + + arg: T extends unknown ? { animal: T } : never, +>arg : Symbol(arg, Decl(genericFunctionParametersConditionalType1.ts, 37, 63)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 37, 42)) +>animal : Symbol(animal, Decl(genericFunctionParametersConditionalType1.ts, 38, 28)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 37, 42)) + +) => void; + +type Result2 = Parameters; +>Result2 : Symbol(Result2, Decl(genericFunctionParametersConditionalType1.ts, 39, 10)) +>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --)) +>WithDistributiveConditionalNested : Symbol(WithDistributiveConditionalNested, Decl(genericFunctionParametersConditionalType1.ts, 35, 70)) + +type WithNonDistributiveConditionalNested = ( +>WithNonDistributiveConditionalNested : Symbol(WithNonDistributiveConditionalNested, Decl(genericFunctionParametersConditionalType1.ts, 41, 61)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 43, 45)) +>Cat : Symbol(Cat, Decl(genericFunctionParametersConditionalType1.ts, 27, 37)) +>Dog : Symbol(Dog, Decl(genericFunctionParametersConditionalType1.ts, 28, 50)) + + arg: [T] extends [unknown] ? { animal: T } : never, +>arg : Symbol(arg, Decl(genericFunctionParametersConditionalType1.ts, 43, 66)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 43, 45)) +>animal : Symbol(animal, Decl(genericFunctionParametersConditionalType1.ts, 44, 32)) +>T : Symbol(T, Decl(genericFunctionParametersConditionalType1.ts, 43, 45)) + +) => void; + +type Result3 = Parameters; +>Result3 : Symbol(Result3, Decl(genericFunctionParametersConditionalType1.ts, 45, 10)) +>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --)) +>WithNonDistributiveConditionalNested : Symbol(WithNonDistributiveConditionalNested, Decl(genericFunctionParametersConditionalType1.ts, 41, 61)) + diff --git a/tests/baselines/reference/genericFunctionParametersConditionalType1.types b/tests/baselines/reference/genericFunctionParametersConditionalType1.types new file mode 100644 index 0000000000000..35467c015c815 --- /dev/null +++ b/tests/baselines/reference/genericFunctionParametersConditionalType1.types @@ -0,0 +1,131 @@ +//// [tests/cases/compiler/genericFunctionParametersConditionalType1.ts] //// + +=== genericFunctionParametersConditionalType1.ts === +// https://github.com/microsoft/TypeScript/issues/62079 + +export {}; + +interface _Map { + foo: { a: 123 } +>foo : { a: 123; } +> : ^^^^^ ^^^ +>a : 123 +> : ^^^ +} + +type ModuleSubType = "bar" & { brand: true }; +>ModuleSubType : ModuleSubType +> : ^^^^^^^^^^^^^ +>brand : true +> : ^^^^ +>true : true +> : ^^^^ + +type Map = _Map & Record +>Map : Map +> : ^^^ +>blah : string +> : ^^^^^^ + +type SubTypeGet< +>SubTypeGet : SubTypeGet +> : ^^^^^^^^^^^^^^^^^^^^^^^^ + + SubType extends string, + Map extends Record, +> = SubType extends unknown +? { type?: SubType } & Map[SubType] +>type : SubType | undefined +> : ^^^^^^^^^^^^^^^^^^^ + +: never; + +type TestParameters = Parameters<(arg: SubTypeGet) => void> +>TestParameters : [arg: { type?: ModuleSubType | undefined; } | ({ type?: "foo" | undefined; } & { a: 123; })] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ +>arg : SubTypeGet +> : ^^^^^^^^^^^^^^^^^^ + +declare class Test { +>Test : Test +> : ^^^^^^^ + + constructor(arg: SubTypeGet); +>arg : SubTypeGet +> : ^^^^^^^^^^^^^^^^^^ +} + +type TestConstructorParameters = ConstructorParameters; +>TestConstructorParameters : [arg: { type?: ModuleSubType | undefined; } | ({ type?: "foo" | undefined; } & { a: 123; })] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^ +>Test : typeof Test +> : ^^^^^^^^^^^ + +declare class Animal { eat(): void; } +>Animal : Animal +> : ^^^^^^ +>eat : () => void +> : ^^^^^^ + +declare class Cat extends Animal { meow(): void; } +>Cat : Cat +> : ^^^ +>Animal : Animal +> : ^^^^^^ +>meow : () => void +> : ^^^^^^ + +declare class Dog extends Animal { bark(): void; } +>Dog : Dog +> : ^^^ +>Animal : Animal +> : ^^^^^^ +>bark : () => void +> : ^^^^^^ + +type WithDistributiveConditionalDirectlyInParam = ( +>WithDistributiveConditionalDirectlyInParam : WithDistributiveConditionalDirectlyInParam +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + arg: T extends unknown ? T : never, +>arg : T extends unknown ? T : never +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +) => void; + +type Result1 = Parameters; +>Result1 : [arg: Cat | Dog] +> : ^^^^^^^^^^^^^^^^ + +type WithDistributiveConditionalNested = ( +>WithDistributiveConditionalNested : WithDistributiveConditionalNested +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + arg: T extends unknown ? { animal: T } : never, +>arg : T extends unknown ? { animal: T; } : never +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ +>animal : T +> : ^ + +) => void; + +type Result2 = Parameters; +>Result2 : [arg: { animal: Cat; } | { animal: Dog; }] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +type WithNonDistributiveConditionalNested = ( +>WithNonDistributiveConditionalNested : WithNonDistributiveConditionalNested +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + arg: [T] extends [unknown] ? { animal: T } : never, +>arg : [T] extends [unknown] ? { animal: T; } : never +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ +>animal : T +> : ^ + +) => void; + +type Result3 = Parameters; +>Result3 : [arg: { animal: Cat | Dog; }] +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/baselines/reference/inferToDistributiveConditionalType1.symbols b/tests/baselines/reference/inferToDistributiveConditionalType1.symbols new file mode 100644 index 0000000000000..4f000ccc00536 --- /dev/null +++ b/tests/baselines/reference/inferToDistributiveConditionalType1.symbols @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/inferToDistributiveConditionalType1.ts] //// + +=== inferToDistributiveConditionalType1.ts === +declare class Animal { eat(): void; } +>Animal : Symbol(Animal, Decl(inferToDistributiveConditionalType1.ts, 0, 0)) +>eat : Symbol(Animal.eat, Decl(inferToDistributiveConditionalType1.ts, 0, 22)) + +declare class Cat extends Animal { meow(): void; } +>Cat : Symbol(Cat, Decl(inferToDistributiveConditionalType1.ts, 0, 37)) +>Animal : Symbol(Animal, Decl(inferToDistributiveConditionalType1.ts, 0, 0)) +>meow : Symbol(Cat.meow, Decl(inferToDistributiveConditionalType1.ts, 1, 34)) + +declare class Dog extends Animal { bark(): void; } +>Dog : Symbol(Dog, Decl(inferToDistributiveConditionalType1.ts, 1, 50)) +>Animal : Symbol(Animal, Decl(inferToDistributiveConditionalType1.ts, 0, 0)) +>bark : Symbol(Dog.bark, Decl(inferToDistributiveConditionalType1.ts, 2, 34)) + +declare function test1(a: T extends unknown ? { prop: T } : never): T; +>test1 : Symbol(test1, Decl(inferToDistributiveConditionalType1.ts, 2, 50)) +>T : Symbol(T, Decl(inferToDistributiveConditionalType1.ts, 4, 23)) +>a : Symbol(a, Decl(inferToDistributiveConditionalType1.ts, 4, 26)) +>T : Symbol(T, Decl(inferToDistributiveConditionalType1.ts, 4, 23)) +>prop : Symbol(prop, Decl(inferToDistributiveConditionalType1.ts, 4, 50)) +>T : Symbol(T, Decl(inferToDistributiveConditionalType1.ts, 4, 23)) +>T : Symbol(T, Decl(inferToDistributiveConditionalType1.ts, 4, 23)) + +declare const arg1: { prop: Dog } | { prop: Cat }; +>arg1 : Symbol(arg1, Decl(inferToDistributiveConditionalType1.ts, 5, 13)) +>prop : Symbol(prop, Decl(inferToDistributiveConditionalType1.ts, 5, 21)) +>Dog : Symbol(Dog, Decl(inferToDistributiveConditionalType1.ts, 1, 50)) +>prop : Symbol(prop, Decl(inferToDistributiveConditionalType1.ts, 5, 37)) +>Cat : Symbol(Cat, Decl(inferToDistributiveConditionalType1.ts, 0, 37)) + +const result1 = test1(arg1); +>result1 : Symbol(result1, Decl(inferToDistributiveConditionalType1.ts, 6, 5)) +>test1 : Symbol(test1, Decl(inferToDistributiveConditionalType1.ts, 2, 50)) +>arg1 : Symbol(arg1, Decl(inferToDistributiveConditionalType1.ts, 5, 13)) + diff --git a/tests/baselines/reference/inferToDistributiveConditionalType1.types b/tests/baselines/reference/inferToDistributiveConditionalType1.types new file mode 100644 index 0000000000000..83309450eb075 --- /dev/null +++ b/tests/baselines/reference/inferToDistributiveConditionalType1.types @@ -0,0 +1,51 @@ +//// [tests/cases/compiler/inferToDistributiveConditionalType1.ts] //// + +=== inferToDistributiveConditionalType1.ts === +declare class Animal { eat(): void; } +>Animal : Animal +> : ^^^^^^ +>eat : () => void +> : ^^^^^^ + +declare class Cat extends Animal { meow(): void; } +>Cat : Cat +> : ^^^ +>Animal : Animal +> : ^^^^^^ +>meow : () => void +> : ^^^^^^ + +declare class Dog extends Animal { bark(): void; } +>Dog : Dog +> : ^^^ +>Animal : Animal +> : ^^^^^^ +>bark : () => void +> : ^^^^^^ + +declare function test1(a: T extends unknown ? { prop: T } : never): T; +>test1 : (a: T extends unknown ? { prop: T; } : never) => T +> : ^ ^^ ^^ ^^^^^ +>a : T extends unknown ? { prop: T; } : never +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^ +>prop : T +> : ^ + +declare const arg1: { prop: Dog } | { prop: Cat }; +>arg1 : { prop: Dog; } | { prop: Cat; } +> : ^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ +>prop : Dog +> : ^^^ +>prop : Cat +> : ^^^ + +const result1 = test1(arg1); +>result1 : Cat | Dog +> : ^^^^^^^^^ +>test1(arg1) : Cat | Dog +> : ^^^^^^^^^ +>test1 : (a: T extends unknown ? { prop: T; } : never) => T +> : ^ ^^ ^^ ^^^^^ +>arg1 : { prop: Dog; } | { prop: Cat; } +> : ^^^^^^^^ ^^^^^^^^^^^^^^ ^^^ + diff --git a/tests/baselines/reference/inferToDistributiveConditionalTypeAndOtherTargets1.symbols b/tests/baselines/reference/inferToDistributiveConditionalTypeAndOtherTargets1.symbols new file mode 100644 index 0000000000000..a1bc70bb7a965 --- /dev/null +++ b/tests/baselines/reference/inferToDistributiveConditionalTypeAndOtherTargets1.symbols @@ -0,0 +1,170 @@ +//// [tests/cases/compiler/inferToDistributiveConditionalTypeAndOtherTargets1.ts] //// + +=== inferToDistributiveConditionalTypeAndOtherTargets1.ts === +type NonUndefinedGuard = T extends undefined ? never : T; +>NonUndefinedGuard : Symbol(NonUndefinedGuard, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 0, 0)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 0, 23)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 0, 23)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 0, 23)) + +declare const RefSymbol: unique symbol; +>RefSymbol : Symbol(RefSymbol, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 2, 13)) + +interface Ref { +>Ref : Symbol(Ref, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 2, 39)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 14)) +>S : Symbol(S, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 22)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 14)) + + get value(): T; +>value : Symbol(Ref.value, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 31), Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 5, 17)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 14)) + + set value(_: S); +>value : Symbol(Ref.value, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 31), Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 5, 17)) +>_ : Symbol(_, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 6, 12)) +>S : Symbol(S, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 4, 22)) + + [RefSymbol]: true; +>[RefSymbol] : Symbol(Ref[RefSymbol], Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 6, 18)) +>RefSymbol : Symbol(RefSymbol, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 2, 13)) +} + +type MaybeRef = Ref | T; +>MaybeRef : Symbol(MaybeRef, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 8, 1)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 10, 14)) +>Ref : Symbol(Ref, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 2, 39)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 10, 14)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 10, 14)) + +type MaybeRefDeep = MaybeRef< +>MaybeRefDeep : Symbol(MaybeRefDeep, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 10, 30)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) +>MaybeRef : Symbol(MaybeRef, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 8, 1)) + + T extends Function +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + + ? T +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) + + : T extends object +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) + + ? { + [Property in keyof T]: MaybeRefDeep; +>Property : Symbol(Property, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 17, 9)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) +>MaybeRefDeep : Symbol(MaybeRefDeep, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 10, 30)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) +>Property : Symbol(Property, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 17, 9)) + } + : T +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 12, 18)) + +>; + +type QueryFunction = () => T | Promise; +>QueryFunction : Symbol(QueryFunction, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 20, 2)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 22, 19)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 22, 19)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 22, 19)) + +type InitialDataFunction = () => T | undefined; +>InitialDataFunction : Symbol(InitialDataFunction, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 22, 55)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 24, 25)) +>T : Symbol(T, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 24, 25)) + +interface QueryOptions { +>QueryOptions : Symbol(QueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 24, 50)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 23)) +>TData : Symbol(TData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 46)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 23)) + + queryFn?: QueryFunction; +>queryFn : Symbol(QueryOptions.queryFn, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 70)) +>QueryFunction : Symbol(QueryFunction, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 20, 2)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 23)) + + initialData?: TData | InitialDataFunction; +>initialData : Symbol(QueryOptions.initialData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 27, 40)) +>TData : Symbol(TData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 46)) +>InitialDataFunction : Symbol(InitialDataFunction, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 22, 55)) +>TData : Symbol(TData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 26, 46)) +} + +type UseQueryOptions = { +>UseQueryOptions : Symbol(UseQueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 29, 1)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 21)) +>TQueryData : Symbol(TQueryData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 44)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 21)) + + [Property in keyof QueryOptions]: MaybeRefDeep< +>Property : Symbol(Property, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 32, 3)) +>QueryOptions : Symbol(QueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 24, 50)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 21)) +>TQueryData : Symbol(TQueryData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 44)) +>MaybeRefDeep : Symbol(MaybeRefDeep, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 10, 30)) + + QueryOptions[Property] +>QueryOptions : Symbol(QueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 24, 50)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 21)) +>TQueryData : Symbol(TQueryData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 31, 44)) +>Property : Symbol(Property, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 32, 3)) + + >; +}; + +type DefinedInitialQueryOptions = UseQueryOptions< +>DefinedInitialQueryOptions : Symbol(DefinedInitialQueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 35, 2)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 37, 32)) +>UseQueryOptions : Symbol(UseQueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 29, 1)) + + TQueryFnData, +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 37, 32)) + + TQueryFnData +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 37, 32)) + +> & { + initialData: +>initialData : Symbol(initialData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 40, 5)) + + | NonUndefinedGuard +>NonUndefinedGuard : Symbol(NonUndefinedGuard, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 0, 0)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 37, 32)) + + | (() => NonUndefinedGuard); +>NonUndefinedGuard : Symbol(NonUndefinedGuard, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 0, 0)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 37, 32)) + +}; + +declare function queryOptions( +>queryOptions : Symbol(queryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 44, 2)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 46, 30)) + + options: DefinedInitialQueryOptions, +>options : Symbol(options, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 46, 54)) +>DefinedInitialQueryOptions : Symbol(DefinedInitialQueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 35, 2)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 46, 30)) + +): DefinedInitialQueryOptions; +>DefinedInitialQueryOptions : Symbol(DefinedInitialQueryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 35, 2)) +>TQueryFnData : Symbol(TQueryFnData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 46, 30)) + +const result = queryOptions({ +>result : Symbol(result, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 50, 5)) +>queryOptions : Symbol(queryOptions, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 44, 2)) + + initialData: () => ({ +>initialData : Symbol(initialData, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 50, 29)) + + wow: true, +>wow : Symbol(wow, Decl(inferToDistributiveConditionalTypeAndOtherTargets1.ts, 51, 23)) + + }), +}); + diff --git a/tests/baselines/reference/inferToDistributiveConditionalTypeAndOtherTargets1.types b/tests/baselines/reference/inferToDistributiveConditionalTypeAndOtherTargets1.types new file mode 100644 index 0000000000000..66b064290c909 --- /dev/null +++ b/tests/baselines/reference/inferToDistributiveConditionalTypeAndOtherTargets1.types @@ -0,0 +1,129 @@ +//// [tests/cases/compiler/inferToDistributiveConditionalTypeAndOtherTargets1.ts] //// + +=== inferToDistributiveConditionalTypeAndOtherTargets1.ts === +type NonUndefinedGuard = T extends undefined ? never : T; +>NonUndefinedGuard : NonUndefinedGuard +> : ^^^^^^^^^^^^^^^^^^^^ + +declare const RefSymbol: unique symbol; +>RefSymbol : unique symbol +> : ^^^^^^^^^^^^^ + +interface Ref { + get value(): T; +>value : T +> : ^ + + set value(_: S); +>value : T +> : ^ +>_ : S +> : ^ + + [RefSymbol]: true; +>[RefSymbol] : true +> : ^^^^ +>RefSymbol : unique symbol +> : ^^^^^^^^^^^^^ +>true : true +> : ^^^^ +} + +type MaybeRef = Ref | T; +>MaybeRef : MaybeRef +> : ^^^^^^^^^^^ + +type MaybeRefDeep = MaybeRef< +>MaybeRefDeep : MaybeRefDeep +> : ^^^^^^^^^^^^^^^ + + T extends Function + ? T + : T extends object + ? { + [Property in keyof T]: MaybeRefDeep; + } + : T +>; + +type QueryFunction = () => T | Promise; +>QueryFunction : QueryFunction +> : ^^^^^^^^^^^^^^^^ + +type InitialDataFunction = () => T | undefined; +>InitialDataFunction : InitialDataFunction +> : ^^^^^^^^^^^^^^^^^^^^^^ + +interface QueryOptions { + queryFn?: QueryFunction; +>queryFn : QueryFunction | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + initialData?: TData | InitialDataFunction; +>initialData : TData | InitialDataFunction | undefined +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +} + +type UseQueryOptions = { +>UseQueryOptions : UseQueryOptions +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + [Property in keyof QueryOptions]: MaybeRefDeep< + QueryOptions[Property] + >; +}; + +type DefinedInitialQueryOptions = UseQueryOptions< +>DefinedInitialQueryOptions : DefinedInitialQueryOptions +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + TQueryFnData, + TQueryFnData +> & { + initialData: +>initialData : NonUndefinedGuard | (() => NonUndefinedGuard) +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ + + | NonUndefinedGuard + | (() => NonUndefinedGuard); +}; + +declare function queryOptions( +>queryOptions : (options: DefinedInitialQueryOptions) => DefinedInitialQueryOptions +> : ^ ^^^^^^^^^^^^ ^^ ^^^^^ + + options: DefinedInitialQueryOptions, +>options : DefinedInitialQueryOptions +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +): DefinedInitialQueryOptions; + +const result = queryOptions({ +>result : DefinedInitialQueryOptions<{ wow: boolean; }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>queryOptions({ initialData: () => ({ wow: true, }),}) : DefinedInitialQueryOptions<{ wow: boolean; }> +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>queryOptions : (options: DefinedInitialQueryOptions) => DefinedInitialQueryOptions +> : ^ ^^^^^^^^^^^^ ^^ ^^^^^ +>{ initialData: () => ({ wow: true, }),} : { initialData: () => { wow: boolean; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + initialData: () => ({ +>initialData : () => { wow: boolean; } +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>() => ({ wow: true, }) : () => { wow: boolean; } +> : ^^^^^^^^^^^^^^^^^^^^^^^ +>({ wow: true, }) : { wow: true; } +> : ^^^^^^^^^^^^^^ +>{ wow: true, } : { wow: true; } +> : ^^^^^^^^^^^^^^ + + wow: true, +>wow : true +> : ^^^^ +>true : true +> : ^^^^ + + }), +}); + diff --git a/tests/cases/compiler/genericFunctionParametersConditionalType1.ts b/tests/cases/compiler/genericFunctionParametersConditionalType1.ts new file mode 100644 index 0000000000000..7bcce5c36b83a --- /dev/null +++ b/tests/cases/compiler/genericFunctionParametersConditionalType1.ts @@ -0,0 +1,51 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/62079 + +export {}; + +interface _Map { + foo: { a: 123 } +} + +type ModuleSubType = "bar" & { brand: true }; + +type Map = _Map & Record + +type SubTypeGet< + SubType extends string, + Map extends Record, +> = SubType extends unknown +? { type?: SubType } & Map[SubType] +: never; + +type TestParameters = Parameters<(arg: SubTypeGet) => void> + +declare class Test { + constructor(arg: SubTypeGet); +} + +type TestConstructorParameters = ConstructorParameters; + +declare class Animal { eat(): void; } +declare class Cat extends Animal { meow(): void; } +declare class Dog extends Animal { bark(): void; } + +type WithDistributiveConditionalDirectlyInParam = ( + arg: T extends unknown ? T : never, +) => void; + +type Result1 = Parameters; + +type WithDistributiveConditionalNested = ( + arg: T extends unknown ? { animal: T } : never, +) => void; + +type Result2 = Parameters; + +type WithNonDistributiveConditionalNested = ( + arg: [T] extends [unknown] ? { animal: T } : never, +) => void; + +type Result3 = Parameters; diff --git a/tests/cases/compiler/inferToDistributiveConditionalType1.ts b/tests/cases/compiler/inferToDistributiveConditionalType1.ts new file mode 100644 index 0000000000000..fb93b9a0252fe --- /dev/null +++ b/tests/cases/compiler/inferToDistributiveConditionalType1.ts @@ -0,0 +1,10 @@ +// @strict: true +// @noEmit: true + +declare class Animal { eat(): void; } +declare class Cat extends Animal { meow(): void; } +declare class Dog extends Animal { bark(): void; } + +declare function test1(a: T extends unknown ? { prop: T } : never): T; +declare const arg1: { prop: Dog } | { prop: Cat }; +const result1 = test1(arg1); diff --git a/tests/cases/compiler/inferToDistributiveConditionalTypeAndOtherTargets1.ts b/tests/cases/compiler/inferToDistributiveConditionalTypeAndOtherTargets1.ts new file mode 100644 index 0000000000000..6ccb06931a99f --- /dev/null +++ b/tests/cases/compiler/inferToDistributiveConditionalTypeAndOtherTargets1.ts @@ -0,0 +1,58 @@ +// @strict: true +// @noEmit: true + +type NonUndefinedGuard = T extends undefined ? never : T; + +declare const RefSymbol: unique symbol; + +interface Ref { + get value(): T; + set value(_: S); + [RefSymbol]: true; +} + +type MaybeRef = Ref | T; + +type MaybeRefDeep = MaybeRef< + T extends Function + ? T + : T extends object + ? { + [Property in keyof T]: MaybeRefDeep; + } + : T +>; + +type QueryFunction = () => T | Promise; + +type InitialDataFunction = () => T | undefined; + +interface QueryOptions { + queryFn?: QueryFunction; + initialData?: TData | InitialDataFunction; +} + +type UseQueryOptions = { + [Property in keyof QueryOptions]: MaybeRefDeep< + QueryOptions[Property] + >; +}; + +type DefinedInitialQueryOptions = UseQueryOptions< + TQueryFnData, + TQueryFnData +> & { + initialData: + | NonUndefinedGuard + | (() => NonUndefinedGuard); +}; + +declare function queryOptions( + options: DefinedInitialQueryOptions, +): DefinedInitialQueryOptions; + +const result = queryOptions({ + initialData: () => ({ + wow: true, + }), +});