From 19260d18e2cde7c4c427b15ec2878320ab08a8fb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 3 Apr 2022 08:58:59 -0700 Subject: [PATCH 1/3] Use intra-expression inference sites in type argument inference --- src/compiler/checker.ts | 118 +++++++++++++++++++++++++++++----------- src/compiler/types.ts | 7 +++ 2 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 92005a36b655e..11ea348cef621 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21729,6 +21729,9 @@ namespace ts { const inference = inferences[i]; if (t === inference.typeParameter) { if (fix && !inference.isFixed) { + // Before we commit to a particular inference (and thus lock out any further inferences), + // we infer from any intra-expression inference sites we have collected. + inferFromIntraExpressionSites(context); clearCachedInferences(inferences); inference.isFixed = true; } @@ -21746,6 +21749,37 @@ namespace ts { } } + function addIntraExpressionInferenceSite(context: InferenceContext, node: Expression | MethodDeclaration, type: Type) { + (context.intraExpressionInferenceSites ??= []).push({ node, type }); + } + + // We collect intra-expression inference sites within object and array literals to handle cases where + // inferred types flow between context sensitive element expressions. For example: + // + // declare function foo(arg: [(n: number) => T, (x: T) => void]): void; + // foo([_a => 0, n => n.toFixed()]); + // + // Above, both arrow functions in the tuple argument are context sensitive, thus both are omitted from the + // pass that collects inferences from the non-context sensitive parts of the arguments. In the subsequent + // pass where nothing is omitted, we need to commit to an inference for T in order to contextually type the + // parameter in the second arrow function, but we want to first infer from the return type of the first + // arrow function. This happens automatically when the arrow functions are discrete arguments (because we + // infer from each argument before processing the next), but when the arrow functions are elements of an + // object or array literal, we need to perform intra-expression inferences early. + function inferFromIntraExpressionSites(context: InferenceContext) { + if (context.intraExpressionInferenceSites) { + for (const { node, type } of context.intraExpressionInferenceSites) { + const contextualType = node.kind === SyntaxKind.MethodDeclaration ? + getContextualTypeForObjectLiteralMethod(node as MethodDeclaration, ContextFlags.NoConstraints) : + getContextualType(node, ContextFlags.NoConstraints); + if (contextualType) { + inferTypes(context.inferences, type, contextualType); + } + } + context.intraExpressionInferenceSites = undefined; + } + } + function createInferenceInfo(typeParameter: TypeParameter): InferenceInfo { return { typeParameter, @@ -27408,6 +27442,11 @@ namespace ts { const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType, forceTuple); elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); + if (contextualType && someType(contextualType, isTupleLikeType) && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { + const inferenceContext = getInferenceContext(node); + Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context + addIntraExpressionInferenceSite(inferenceContext, e, type); + } } } if (inDestructuringPattern) { @@ -27625,6 +27664,14 @@ namespace ts { prop.target = member; member = prop; allPropertiesTable?.set(prop.escapedName, prop); + + if (contextualType && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && + (memberDecl.kind === SyntaxKind.PropertyAssignment || memberDecl.kind === SyntaxKind.MethodDeclaration) && isContextSensitive(memberDecl)) { + const inferenceContext = getInferenceContext(node); + Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context + const inferenceNode = memberDecl.kind === SyntaxKind.PropertyAssignment ? memberDecl.initializer : memberDecl; + addIntraExpressionInferenceSite(inferenceContext, inferenceNode, type); + } } else if (memberDecl.kind === SyntaxKind.SpreadAssignment) { if (languageVersion < ScriptTarget.ES2015) { @@ -29727,34 +29774,36 @@ namespace ts { if (node.kind !== SyntaxKind.Decorator) { const contextualType = getContextualType(node, every(signature.typeParameters, p => !!getDefaultFromTypeParameter(p)) ? ContextFlags.SkipBindingPatterns : ContextFlags.None); if (contextualType) { - // We clone the inference context to avoid disturbing a resolution in progress for an - // outer call expression. Effectively we just want a snapshot of whatever has been - // inferred for any outer call expression so far. - const outerContext = getInferenceContext(node); - const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); - const instantiatedType = instantiateType(contextualType, outerMapper); - // If the contextual type is a generic function type with a single call signature, we - // instantiate the type with its own type parameters and type arguments. This ensures that - // the type parameters are not erased to type any during type inference such that they can - // be inferred as actual types from the contextual type. For example: - // declare function arrayMap(f: (x: T) => U): (a: T[]) => U[]; - // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); - // Above, the type of the 'value' parameter is inferred to be 'A'. - const contextualSignature = getSingleCallSignature(instantiatedType); - const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? - getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : - instantiatedType; const inferenceTargetType = getReturnTypeOfSignature(signature); - // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); - // Create a type mapper for instantiating generic contextual types using the inferences made - // from the return type. We need a separate inference pass here because (a) instantiation of - // the source type uses the outer context's return mapper (which excludes inferences made from - // outer arguments), and (b) we don't want any further inferences going into this context. - const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); - const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); - inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); - context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; + if (couldContainTypeVariables(inferenceTargetType)) { + // We clone the inference context to avoid disturbing a resolution in progress for an + // outer call expression. Effectively we just want a snapshot of whatever has been + // inferred for any outer call expression so far. + const outerContext = getInferenceContext(node); + const outerMapper = getMapperFromContext(cloneInferenceContext(outerContext, InferenceFlags.NoDefault)); + const instantiatedType = instantiateType(contextualType, outerMapper); + // If the contextual type is a generic function type with a single call signature, we + // instantiate the type with its own type parameters and type arguments. This ensures that + // the type parameters are not erased to type any during type inference such that they can + // be inferred as actual types from the contextual type. For example: + // declare function arrayMap(f: (x: T) => U): (a: T[]) => U[]; + // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); + // Above, the type of the 'value' parameter is inferred to be 'A'. + const contextualSignature = getSingleCallSignature(instantiatedType); + const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? + getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(contextualSignature, contextualSignature.typeParameters)) : + instantiatedType; + // Inferences made from return types have lower priority than all other inferences. + inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); + // Create a type mapper for instantiating generic contextual types using the inferences made + // from the return type. We need a separate inference pass here because (a) instantiation of + // the source type uses the outer context's return mapper (which excludes inferences made from + // outer arguments), and (b) we don't want any further inferences going into this context. + const returnContext = createInferenceContext(signature.typeParameters!, signature, context.flags); + const returnSourceType = instantiateType(contextualType, outerContext && outerContext.returnMapper); + inferTypes(returnContext.inferences, returnSourceType, inferenceTargetType); + context.returnMapper = some(returnContext.inferences, hasInferenceCandidates) ? getMapperFromContext(cloneInferredPartOfContext(returnContext)) : undefined; + } } } @@ -29768,7 +29817,7 @@ namespace ts { } const thisType = getThisTypeOfSignature(signature); - if (thisType) { + if (thisType && couldContainTypeVariables(thisType)) { const thisArgumentNode = getThisArgumentOfCall(node); inferTypes(context.inferences, getThisArgumentType(thisArgumentNode), thisType); } @@ -29777,12 +29826,14 @@ namespace ts { const arg = args[i]; if (arg.kind !== SyntaxKind.OmittedExpression && !(checkMode & CheckMode.IsForStringLiteralArgumentCompletions && hasSkipDirectInferenceFlag(arg))) { const paramType = getTypeAtPosition(signature, i); - const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); - inferTypes(context.inferences, argType, paramType); + if (couldContainTypeVariables(paramType)) { + const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode); + inferTypes(context.inferences, argType, paramType); + } } } - if (restType) { + if (restType && couldContainTypeVariables(restType)) { const spreadType = getSpreadArgumentType(args, argCount, args.length, restType, context, checkMode); inferTypes(context.inferences, spreadType, restType); } @@ -34141,6 +34192,11 @@ namespace ts { context.contextualType = contextualType; context.inferenceContext = inferenceContext; const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); + // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type + // parameters. This information is no longer needed after the call to checkExpression. + if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { + inferenceContext.intraExpressionInferenceSites = undefined; + } // We strip literal freshness when an appropriate contextual type is present such that contextually typed // literals always preserve their literal types (otherwise they might widen during type inference). An alternative // here would be to not mark contextually typed literals as fresh in the first place. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5180c765990bb..f003b4c319f53 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5913,6 +5913,13 @@ namespace ts { nonFixingMapper: TypeMapper; // Mapper that doesn't fix inferences returnMapper?: TypeMapper; // Type mapper for inferences from return types (if any) inferredTypeParameters?: readonly TypeParameter[]; // Inferred type parameters for function result + intraExpressionInferenceSites?: IntraExpressionInferenceSite[]; + } + + /* @internal */ + export interface IntraExpressionInferenceSite { + node: Expression | MethodDeclaration; + type: Type; } /* @internal */ From ac9d3340123aa04c0a09c2490adda565aeb5910f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 3 Apr 2022 08:59:20 -0700 Subject: [PATCH 2/3] Accept new baselines --- .../contextualTypingOfOptionalMembers.types | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/baselines/reference/contextualTypingOfOptionalMembers.types b/tests/baselines/reference/contextualTypingOfOptionalMembers.types index 8f2d051149a40..192d5b524938f 100644 --- a/tests/baselines/reference/contextualTypingOfOptionalMembers.types +++ b/tests/baselines/reference/contextualTypingOfOptionalMembers.types @@ -25,7 +25,7 @@ declare function app>(obj: Optionsapp({ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,}) : void >app : >(obj: Options) => void ->{ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,} : { state: number; actions: { foo: (s: number) => number; }; view: (s: number, a: ActionsObject) => any; } +>{ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,} : { state: number; actions: { foo: (s: number) => number; }; view: (s: number, a: { foo: (s: number) => number; }) => any; } state: 100, >state : number @@ -43,10 +43,10 @@ app({ }, view: (s, a) => undefined as any, ->view : (s: number, a: ActionsObject) => any ->(s, a) => undefined as any : (s: number, a: ActionsObject) => any +>view : (s: number, a: { foo: (s: number) => number; }) => any +>(s, a) => undefined as any : (s: number, a: { foo: (s: number) => number; }) => any >s : number ->a : ActionsObject +>a : { foo: (s: number) => number; } >undefined as any : any >undefined : undefined @@ -95,7 +95,7 @@ declare function app2>(obj: Options2 app2({ >app2({ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,}) : void >app2 : >(obj: Options2) => void ->{ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,} : { state: number; actions: { foo: (s: number) => number; }; view: (s: number, a: ActionsObject) => any; } +>{ state: 100, actions: { foo: s => s // Should be typed number => number }, view: (s, a) => undefined as any,} : { state: number; actions: { foo: (s: number) => number; }; view: (s: number, a: { foo: (s: number) => number; }) => any; } state: 100, >state : number @@ -113,10 +113,10 @@ app2({ }, view: (s, a) => undefined as any, ->view : (s: number, a: ActionsObject) => any ->(s, a) => undefined as any : (s: number, a: ActionsObject) => any +>view : (s: number, a: { foo: (s: number) => number; }) => any +>(s, a) => undefined as any : (s: number, a: { foo: (s: number) => number; }) => any >s : number ->a : ActionsObject +>a : { foo: (s: number) => number; } >undefined as any : any >undefined : undefined @@ -134,7 +134,7 @@ declare function app3>(obj: Optionsapp3({ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,}) : void >app3 : >(obj: Options) => void ->{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ActionsArray) => any; } +>{ state: 100, actions: [ s => s // Should be typed number => number ], view: (s, a) => undefined as any,} : { state: number; actions: ((s: number) => number)[]; view: (s: number, a: ((s: number) => number)[]) => any; } state: 100, >state : number @@ -151,10 +151,10 @@ app3({ ], view: (s, a) => undefined as any, ->view : (s: number, a: ActionsArray) => any ->(s, a) => undefined as any : (s: number, a: ActionsArray) => any +>view : (s: number, a: ((s: number) => number)[]) => any +>(s, a) => undefined as any : (s: number, a: ((s: number) => number)[]) => any >s : number ->a : ActionsArray +>a : ((s: number) => number)[] >undefined as any : any >undefined : undefined From 900ef9166091100779f123cd7bb06281fde01529 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 3 Apr 2022 09:21:10 -0700 Subject: [PATCH 3/3] Add tests --- .../intraExpressionInferences.errors.txt | 192 ++++++ .../reference/intraExpressionInferences.js | 342 ++++++++++ .../intraExpressionInferences.symbols | 560 +++++++++++++++++ .../reference/intraExpressionInferences.types | 590 ++++++++++++++++++ .../intraExpressionInferences.ts | 178 ++++++ 5 files changed, 1862 insertions(+) create mode 100644 tests/baselines/reference/intraExpressionInferences.errors.txt create mode 100644 tests/baselines/reference/intraExpressionInferences.js create mode 100644 tests/baselines/reference/intraExpressionInferences.symbols create mode 100644 tests/baselines/reference/intraExpressionInferences.types create mode 100644 tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts diff --git a/tests/baselines/reference/intraExpressionInferences.errors.txt b/tests/baselines/reference/intraExpressionInferences.errors.txt new file mode 100644 index 0000000000000..e4d3548c45740 --- /dev/null +++ b/tests/baselines/reference/intraExpressionInferences.errors.txt @@ -0,0 +1,192 @@ +tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts(123,5): error TS2322: Type '(inputs: Unwrap<{ num: Wrapper; str: Wrapper; }>) => { bool: any; str: number; }' is not assignable to type '(inputs: Unwrap<{ num: Wrapper; str: Wrapper; }>) => Unwrap<{ bool: Wrapper; str: Wrapper; }>'. + Call signature return types '{ bool: any; str: number; }' and 'Unwrap<{ bool: Wrapper; str: Wrapper; }>' are incompatible. + The types of 'str' are incompatible between these types. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts(125,26): error TS2339: Property 'nonexistent' does not exist on type 'Unwrap<{ num: Wrapper; str: Wrapper; }>'. + + +==== tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts (2 errors) ==== + // Repros from #47599 + + declare function callIt(obj: { + produce: (n: number) => T, + consume: (x: T) => void + }): void; + + callIt({ + produce: () => 0, + consume: n => n.toFixed() + }); + + callIt({ + produce: _a => 0, + consume: n => n.toFixed(), + }); + + callIt({ + produce() { + return 0; + }, + consume: n => n.toFixed() + }); + + declare function callItT(obj: [(n: number) => T, (x: T) => void]): void; + + callItT([() => 0, n => n.toFixed()]); + callItT([_a => 0, n => n.toFixed()]); + + // Repro from #25092 + + interface MyInterface { + retrieveGeneric: (parameter: string) => T, + operateWithGeneric: (generic: T) => string + } + + const inferTypeFn = (generic: MyInterface) => generic; + + const myGeneric = inferTypeFn({ + retrieveGeneric: parameter => 5, + operateWithGeneric: generic => generic.toFixed() + }); + + // Repro #38623 + + function make(o: { mutations: M, action: (m: M) => void }) { } + + make({ + mutations: { + foo() { } + }, + action: (a) => { a.foo() } + }); + + // Repro from #38845 + + declare function foo(options: { a: A, b: (a: A) => void }): void; + + foo({ + a: () => { return 42 }, + b(a) {}, + }); + + foo({ + a: function () { return 42 }, + b(a) {}, + }); + + foo({ + a() { return 42 }, + b(a) {}, + }); + + // Repro from #38872 + + type Chain = { + a(): R1, + b(a: R1): R2; + c(b: R2): void; + }; + + function test(foo: Chain) {} + + test({ + a: () => 0, + b: (a) => 'a', + c: (b) => { + const x: string = b; + } + }); + + // Repro from #41712 + + class Wrapper { + public value?: T; + } + + type WrappedMap = Record; + type Unwrap = { + [K in keyof D]: D[K] extends Wrapper ? T : never; + }; + + type MappingComponent = { + setup(): { inputs: I; outputs: O }; + map?: (inputs: Unwrap) => Unwrap; + }; + + declare function createMappingComponent(def: MappingComponent): void; + + createMappingComponent({ + setup() { + return { + inputs: { + num: new Wrapper(), + str: new Wrapper() + }, + outputs: { + bool: new Wrapper(), + str: new Wrapper() + } + }; + }, + map(inputs) { + ~~~ +!!! error TS2322: Type '(inputs: Unwrap<{ num: Wrapper; str: Wrapper; }>) => { bool: any; str: number; }' is not assignable to type '(inputs: Unwrap<{ num: Wrapper; str: Wrapper; }>) => Unwrap<{ bool: Wrapper; str: Wrapper; }>'. +!!! error TS2322: Call signature return types '{ bool: any; str: number; }' and 'Unwrap<{ bool: Wrapper; str: Wrapper; }>' are incompatible. +!!! error TS2322: The types of 'str' are incompatible between these types. +!!! error TS2322: Type 'number' is not assignable to type 'string'. +!!! related TS6500 tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts:105:5: The expected type comes from property 'map' which is declared here on type 'MappingComponent<{ num: Wrapper; str: Wrapper; }, { bool: Wrapper; str: Wrapper; }>' + return { + bool: inputs.nonexistent, + ~~~~~~~~~~~ +!!! error TS2339: Property 'nonexistent' does not exist on type 'Unwrap<{ num: Wrapper; str: Wrapper; }>'. + str: inputs.num, // Causes error + } + } + }); + + // Repro from #48279 + + function simplified(props: { generator: () => T, receiver: (t: T) => any }) {} + + function whatIWant(props: { generator: (bob: any) => T, receiver: (t: T) => any }) {} + + function nonObject(generator: (bob: any) => T, receiver: (t: T) => any) {} + + simplified({ generator: () => 123, receiver: (t) => console.log(t + 2) }) + whatIWant({ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) }) + nonObject((bob) => bob ? 1 : 2, (t) => console.log(t + 2)) + + // Repro from #48466 + + interface Opts { + fetch: (params: TParams, foo: number) => TDone, + map: (data: TDone) => TMapped + } + + function example(options: Opts) { + return (params: TParams) => { + const data = options.fetch(params, 123) + return options.map(data) + } + } + + interface Params { + one: number + two: string + } + + example({ + fetch: (params: Params) => 123, + map: (number) => String(number) + }); + + example({ + fetch: (params: Params, foo: number) => 123, + map: (number) => String(number) + }); + + example({ + fetch: (params: Params, foo) => 123, + map: (number) => String(number) + }); + \ No newline at end of file diff --git a/tests/baselines/reference/intraExpressionInferences.js b/tests/baselines/reference/intraExpressionInferences.js new file mode 100644 index 0000000000000..20647b46897cf --- /dev/null +++ b/tests/baselines/reference/intraExpressionInferences.js @@ -0,0 +1,342 @@ +//// [intraExpressionInferences.ts] +// Repros from #47599 + +declare function callIt(obj: { + produce: (n: number) => T, + consume: (x: T) => void +}): void; + +callIt({ + produce: () => 0, + consume: n => n.toFixed() +}); + +callIt({ + produce: _a => 0, + consume: n => n.toFixed(), +}); + +callIt({ + produce() { + return 0; + }, + consume: n => n.toFixed() +}); + +declare function callItT(obj: [(n: number) => T, (x: T) => void]): void; + +callItT([() => 0, n => n.toFixed()]); +callItT([_a => 0, n => n.toFixed()]); + +// Repro from #25092 + +interface MyInterface { + retrieveGeneric: (parameter: string) => T, + operateWithGeneric: (generic: T) => string +} + +const inferTypeFn = (generic: MyInterface) => generic; + +const myGeneric = inferTypeFn({ + retrieveGeneric: parameter => 5, + operateWithGeneric: generic => generic.toFixed() +}); + +// Repro #38623 + +function make(o: { mutations: M, action: (m: M) => void }) { } + +make({ + mutations: { + foo() { } + }, + action: (a) => { a.foo() } +}); + +// Repro from #38845 + +declare function foo(options: { a: A, b: (a: A) => void }): void; + +foo({ + a: () => { return 42 }, + b(a) {}, +}); + +foo({ + a: function () { return 42 }, + b(a) {}, +}); + +foo({ + a() { return 42 }, + b(a) {}, +}); + +// Repro from #38872 + +type Chain = { + a(): R1, + b(a: R1): R2; + c(b: R2): void; +}; + +function test(foo: Chain) {} + +test({ + a: () => 0, + b: (a) => 'a', + c: (b) => { + const x: string = b; + } +}); + +// Repro from #41712 + +class Wrapper { + public value?: T; +} + +type WrappedMap = Record; +type Unwrap = { + [K in keyof D]: D[K] extends Wrapper ? T : never; +}; + +type MappingComponent = { + setup(): { inputs: I; outputs: O }; + map?: (inputs: Unwrap) => Unwrap; +}; + +declare function createMappingComponent(def: MappingComponent): void; + +createMappingComponent({ + setup() { + return { + inputs: { + num: new Wrapper(), + str: new Wrapper() + }, + outputs: { + bool: new Wrapper(), + str: new Wrapper() + } + }; + }, + map(inputs) { + return { + bool: inputs.nonexistent, + str: inputs.num, // Causes error + } + } +}); + +// Repro from #48279 + +function simplified(props: { generator: () => T, receiver: (t: T) => any }) {} + +function whatIWant(props: { generator: (bob: any) => T, receiver: (t: T) => any }) {} + +function nonObject(generator: (bob: any) => T, receiver: (t: T) => any) {} + +simplified({ generator: () => 123, receiver: (t) => console.log(t + 2) }) +whatIWant({ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) }) +nonObject((bob) => bob ? 1 : 2, (t) => console.log(t + 2)) + +// Repro from #48466 + +interface Opts { + fetch: (params: TParams, foo: number) => TDone, + map: (data: TDone) => TMapped +} + +function example(options: Opts) { + return (params: TParams) => { + const data = options.fetch(params, 123) + return options.map(data) + } +} + +interface Params { + one: number + two: string +} + +example({ + fetch: (params: Params) => 123, + map: (number) => String(number) +}); + +example({ + fetch: (params: Params, foo: number) => 123, + map: (number) => String(number) +}); + +example({ + fetch: (params: Params, foo) => 123, + map: (number) => String(number) +}); + + +//// [intraExpressionInferences.js] +"use strict"; +// Repros from #47599 +callIt({ + produce: function () { return 0; }, + consume: function (n) { return n.toFixed(); } +}); +callIt({ + produce: function (_a) { return 0; }, + consume: function (n) { return n.toFixed(); } +}); +callIt({ + produce: function () { + return 0; + }, + consume: function (n) { return n.toFixed(); } +}); +callItT([function () { return 0; }, function (n) { return n.toFixed(); }]); +callItT([function (_a) { return 0; }, function (n) { return n.toFixed(); }]); +var inferTypeFn = function (generic) { return generic; }; +var myGeneric = inferTypeFn({ + retrieveGeneric: function (parameter) { return 5; }, + operateWithGeneric: function (generic) { return generic.toFixed(); } +}); +// Repro #38623 +function make(o) { } +make({ + mutations: { + foo: function () { } + }, + action: function (a) { a.foo(); } +}); +foo({ + a: function () { return 42; }, + b: function (a) { } +}); +foo({ + a: function () { return 42; }, + b: function (a) { } +}); +foo({ + a: function () { return 42; }, + b: function (a) { } +}); +function test(foo) { } +test({ + a: function () { return 0; }, + b: function (a) { return 'a'; }, + c: function (b) { + var x = b; + } +}); +// Repro from #41712 +var Wrapper = /** @class */ (function () { + function Wrapper() { + } + return Wrapper; +}()); +createMappingComponent({ + setup: function () { + return { + inputs: { + num: new Wrapper(), + str: new Wrapper() + }, + outputs: { + bool: new Wrapper(), + str: new Wrapper() + } + }; + }, + map: function (inputs) { + return { + bool: inputs.nonexistent, + str: inputs.num + }; + } +}); +// Repro from #48279 +function simplified(props) { } +function whatIWant(props) { } +function nonObject(generator, receiver) { } +simplified({ generator: function () { return 123; }, receiver: function (t) { return console.log(t + 2); } }); +whatIWant({ generator: function (bob) { return bob ? 1 : 2; }, receiver: function (t) { return console.log(t + 2); } }); +nonObject(function (bob) { return bob ? 1 : 2; }, function (t) { return console.log(t + 2); }); +function example(options) { + return function (params) { + var data = options.fetch(params, 123); + return options.map(data); + }; +} +example({ + fetch: function (params) { return 123; }, + map: function (number) { return String(number); } +}); +example({ + fetch: function (params, foo) { return 123; }, + map: function (number) { return String(number); } +}); +example({ + fetch: function (params, foo) { return 123; }, + map: function (number) { return String(number); } +}); + + +//// [intraExpressionInferences.d.ts] +declare function callIt(obj: { + produce: (n: number) => T; + consume: (x: T) => void; +}): void; +declare function callItT(obj: [(n: number) => T, (x: T) => void]): void; +interface MyInterface { + retrieveGeneric: (parameter: string) => T; + operateWithGeneric: (generic: T) => string; +} +declare const inferTypeFn: (generic: MyInterface) => MyInterface; +declare const myGeneric: MyInterface; +declare function make(o: { + mutations: M; + action: (m: M) => void; +}): void; +declare function foo(options: { + a: A; + b: (a: A) => void; +}): void; +declare type Chain = { + a(): R1; + b(a: R1): R2; + c(b: R2): void; +}; +declare function test(foo: Chain): void; +declare class Wrapper { + value?: T; +} +declare type WrappedMap = Record; +declare type Unwrap = { + [K in keyof D]: D[K] extends Wrapper ? T : never; +}; +declare type MappingComponent = { + setup(): { + inputs: I; + outputs: O; + }; + map?: (inputs: Unwrap) => Unwrap; +}; +declare function createMappingComponent(def: MappingComponent): void; +declare function simplified(props: { + generator: () => T; + receiver: (t: T) => any; +}): void; +declare function whatIWant(props: { + generator: (bob: any) => T; + receiver: (t: T) => any; +}): void; +declare function nonObject(generator: (bob: any) => T, receiver: (t: T) => any): void; +interface Opts { + fetch: (params: TParams, foo: number) => TDone; + map: (data: TDone) => TMapped; +} +declare function example(options: Opts): (params: TParams) => TMapped; +interface Params { + one: number; + two: string; +} diff --git a/tests/baselines/reference/intraExpressionInferences.symbols b/tests/baselines/reference/intraExpressionInferences.symbols new file mode 100644 index 0000000000000..05887ee317b01 --- /dev/null +++ b/tests/baselines/reference/intraExpressionInferences.symbols @@ -0,0 +1,560 @@ +=== tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts === +// Repros from #47599 + +declare function callIt(obj: { +>callIt : Symbol(callIt, Decl(intraExpressionInferences.ts, 0, 0)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 2, 24)) +>obj : Symbol(obj, Decl(intraExpressionInferences.ts, 2, 27)) + + produce: (n: number) => T, +>produce : Symbol(produce, Decl(intraExpressionInferences.ts, 2, 33)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 3, 14)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 2, 24)) + + consume: (x: T) => void +>consume : Symbol(consume, Decl(intraExpressionInferences.ts, 3, 30)) +>x : Symbol(x, Decl(intraExpressionInferences.ts, 4, 14)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 2, 24)) + +}): void; + +callIt({ +>callIt : Symbol(callIt, Decl(intraExpressionInferences.ts, 0, 0)) + + produce: () => 0, +>produce : Symbol(produce, Decl(intraExpressionInferences.ts, 7, 8)) + + consume: n => n.toFixed() +>consume : Symbol(consume, Decl(intraExpressionInferences.ts, 8, 21)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 9, 12)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 9, 12)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +}); + +callIt({ +>callIt : Symbol(callIt, Decl(intraExpressionInferences.ts, 0, 0)) + + produce: _a => 0, +>produce : Symbol(produce, Decl(intraExpressionInferences.ts, 12, 8)) +>_a : Symbol(_a, Decl(intraExpressionInferences.ts, 13, 12)) + + consume: n => n.toFixed(), +>consume : Symbol(consume, Decl(intraExpressionInferences.ts, 13, 21)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 14, 12)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 14, 12)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +}); + +callIt({ +>callIt : Symbol(callIt, Decl(intraExpressionInferences.ts, 0, 0)) + + produce() { +>produce : Symbol(produce, Decl(intraExpressionInferences.ts, 17, 8)) + + return 0; + }, + consume: n => n.toFixed() +>consume : Symbol(consume, Decl(intraExpressionInferences.ts, 20, 6)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 21, 12)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 21, 12)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +}); + +declare function callItT(obj: [(n: number) => T, (x: T) => void]): void; +>callItT : Symbol(callItT, Decl(intraExpressionInferences.ts, 22, 3)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 24, 25)) +>obj : Symbol(obj, Decl(intraExpressionInferences.ts, 24, 28)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 24, 35)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 24, 25)) +>x : Symbol(x, Decl(intraExpressionInferences.ts, 24, 53)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 24, 25)) + +callItT([() => 0, n => n.toFixed()]); +>callItT : Symbol(callItT, Decl(intraExpressionInferences.ts, 22, 3)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 26, 17)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 26, 17)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +callItT([_a => 0, n => n.toFixed()]); +>callItT : Symbol(callItT, Decl(intraExpressionInferences.ts, 22, 3)) +>_a : Symbol(_a, Decl(intraExpressionInferences.ts, 27, 9)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 27, 17)) +>n.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>n : Symbol(n, Decl(intraExpressionInferences.ts, 27, 17)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +// Repro from #25092 + +interface MyInterface { +>MyInterface : Symbol(MyInterface, Decl(intraExpressionInferences.ts, 27, 37)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 31, 22)) + + retrieveGeneric: (parameter: string) => T, +>retrieveGeneric : Symbol(MyInterface.retrieveGeneric, Decl(intraExpressionInferences.ts, 31, 26)) +>parameter : Symbol(parameter, Decl(intraExpressionInferences.ts, 32, 22)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 31, 22)) + + operateWithGeneric: (generic: T) => string +>operateWithGeneric : Symbol(MyInterface.operateWithGeneric, Decl(intraExpressionInferences.ts, 32, 46)) +>generic : Symbol(generic, Decl(intraExpressionInferences.ts, 33, 25)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 31, 22)) +} + +const inferTypeFn = (generic: MyInterface) => generic; +>inferTypeFn : Symbol(inferTypeFn, Decl(intraExpressionInferences.ts, 36, 5)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 36, 21)) +>generic : Symbol(generic, Decl(intraExpressionInferences.ts, 36, 24)) +>MyInterface : Symbol(MyInterface, Decl(intraExpressionInferences.ts, 27, 37)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 36, 21)) +>generic : Symbol(generic, Decl(intraExpressionInferences.ts, 36, 24)) + +const myGeneric = inferTypeFn({ +>myGeneric : Symbol(myGeneric, Decl(intraExpressionInferences.ts, 38, 5)) +>inferTypeFn : Symbol(inferTypeFn, Decl(intraExpressionInferences.ts, 36, 5)) + + retrieveGeneric: parameter => 5, +>retrieveGeneric : Symbol(retrieveGeneric, Decl(intraExpressionInferences.ts, 38, 31)) +>parameter : Symbol(parameter, Decl(intraExpressionInferences.ts, 39, 20)) + + operateWithGeneric: generic => generic.toFixed() +>operateWithGeneric : Symbol(operateWithGeneric, Decl(intraExpressionInferences.ts, 39, 36)) +>generic : Symbol(generic, Decl(intraExpressionInferences.ts, 40, 23)) +>generic.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) +>generic : Symbol(generic, Decl(intraExpressionInferences.ts, 40, 23)) +>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --)) + +}); + +// Repro #38623 + +function make(o: { mutations: M, action: (m: M) => void }) { } +>make : Symbol(make, Decl(intraExpressionInferences.ts, 41, 3)) +>M : Symbol(M, Decl(intraExpressionInferences.ts, 45, 14)) +>o : Symbol(o, Decl(intraExpressionInferences.ts, 45, 17)) +>mutations : Symbol(mutations, Decl(intraExpressionInferences.ts, 45, 21)) +>M : Symbol(M, Decl(intraExpressionInferences.ts, 45, 14)) +>action : Symbol(action, Decl(intraExpressionInferences.ts, 45, 35)) +>m : Symbol(m, Decl(intraExpressionInferences.ts, 45, 46)) +>M : Symbol(M, Decl(intraExpressionInferences.ts, 45, 14)) + +make({ +>make : Symbol(make, Decl(intraExpressionInferences.ts, 41, 3)) + + mutations: { +>mutations : Symbol(mutations, Decl(intraExpressionInferences.ts, 47, 6)) + + foo() { } +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 48, 15)) + + }, + action: (a) => { a.foo() } +>action : Symbol(action, Decl(intraExpressionInferences.ts, 50, 5)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 51, 12)) +>a.foo : Symbol(foo, Decl(intraExpressionInferences.ts, 48, 15)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 51, 12)) +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 48, 15)) + +}); + +// Repro from #38845 + +declare function foo(options: { a: A, b: (a: A) => void }): void; +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 52, 3)) +>A : Symbol(A, Decl(intraExpressionInferences.ts, 56, 21)) +>options : Symbol(options, Decl(intraExpressionInferences.ts, 56, 24)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 56, 34)) +>A : Symbol(A, Decl(intraExpressionInferences.ts, 56, 21)) +>b : Symbol(b, Decl(intraExpressionInferences.ts, 56, 40)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 56, 45)) +>A : Symbol(A, Decl(intraExpressionInferences.ts, 56, 21)) + +foo({ +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 52, 3)) + + a: () => { return 42 }, +>a : Symbol(a, Decl(intraExpressionInferences.ts, 58, 5)) + + b(a) {}, +>b : Symbol(b, Decl(intraExpressionInferences.ts, 59, 27)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 60, 6)) + +}); + +foo({ +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 52, 3)) + + a: function () { return 42 }, +>a : Symbol(a, Decl(intraExpressionInferences.ts, 63, 5)) + + b(a) {}, +>b : Symbol(b, Decl(intraExpressionInferences.ts, 64, 33)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 65, 6)) + +}); + +foo({ +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 52, 3)) + + a() { return 42 }, +>a : Symbol(a, Decl(intraExpressionInferences.ts, 68, 5)) + + b(a) {}, +>b : Symbol(b, Decl(intraExpressionInferences.ts, 69, 22)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 70, 6)) + +}); + +// Repro from #38872 + +type Chain = { +>Chain : Symbol(Chain, Decl(intraExpressionInferences.ts, 71, 3)) +>R1 : Symbol(R1, Decl(intraExpressionInferences.ts, 75, 11)) +>R2 : Symbol(R2, Decl(intraExpressionInferences.ts, 75, 14)) + + a(): R1, +>a : Symbol(a, Decl(intraExpressionInferences.ts, 75, 22)) +>R1 : Symbol(R1, Decl(intraExpressionInferences.ts, 75, 11)) + + b(a: R1): R2; +>b : Symbol(b, Decl(intraExpressionInferences.ts, 76, 12)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 77, 6)) +>R1 : Symbol(R1, Decl(intraExpressionInferences.ts, 75, 11)) +>R2 : Symbol(R2, Decl(intraExpressionInferences.ts, 75, 14)) + + c(b: R2): void; +>c : Symbol(c, Decl(intraExpressionInferences.ts, 77, 17)) +>b : Symbol(b, Decl(intraExpressionInferences.ts, 78, 6)) +>R2 : Symbol(R2, Decl(intraExpressionInferences.ts, 75, 14)) + +}; + +function test(foo: Chain) {} +>test : Symbol(test, Decl(intraExpressionInferences.ts, 79, 2)) +>R1 : Symbol(R1, Decl(intraExpressionInferences.ts, 81, 14)) +>R2 : Symbol(R2, Decl(intraExpressionInferences.ts, 81, 17)) +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 81, 22)) +>Chain : Symbol(Chain, Decl(intraExpressionInferences.ts, 71, 3)) +>R1 : Symbol(R1, Decl(intraExpressionInferences.ts, 81, 14)) +>R2 : Symbol(R2, Decl(intraExpressionInferences.ts, 81, 17)) + +test({ +>test : Symbol(test, Decl(intraExpressionInferences.ts, 79, 2)) + + a: () => 0, +>a : Symbol(a, Decl(intraExpressionInferences.ts, 83, 6)) + + b: (a) => 'a', +>b : Symbol(b, Decl(intraExpressionInferences.ts, 84, 15)) +>a : Symbol(a, Decl(intraExpressionInferences.ts, 85, 8)) + + c: (b) => { +>c : Symbol(c, Decl(intraExpressionInferences.ts, 85, 18)) +>b : Symbol(b, Decl(intraExpressionInferences.ts, 86, 8)) + + const x: string = b; +>x : Symbol(x, Decl(intraExpressionInferences.ts, 87, 13)) +>b : Symbol(b, Decl(intraExpressionInferences.ts, 86, 8)) + } +}); + +// Repro from #41712 + +class Wrapper { +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 93, 14)) + + public value?: T; +>value : Symbol(Wrapper.value, Decl(intraExpressionInferences.ts, 93, 24)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 93, 14)) +} + +type WrappedMap = Record; +>WrappedMap : Symbol(WrappedMap, Decl(intraExpressionInferences.ts, 95, 1)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) + +type Unwrap = { +>Unwrap : Symbol(Unwrap, Decl(intraExpressionInferences.ts, 97, 42)) +>D : Symbol(D, Decl(intraExpressionInferences.ts, 98, 12)) +>WrappedMap : Symbol(WrappedMap, Decl(intraExpressionInferences.ts, 95, 1)) + + [K in keyof D]: D[K] extends Wrapper ? T : never; +>K : Symbol(K, Decl(intraExpressionInferences.ts, 99, 5)) +>D : Symbol(D, Decl(intraExpressionInferences.ts, 98, 12)) +>D : Symbol(D, Decl(intraExpressionInferences.ts, 98, 12)) +>K : Symbol(K, Decl(intraExpressionInferences.ts, 99, 5)) +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 99, 46)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 99, 46)) + +}; + +type MappingComponent = { +>MappingComponent : Symbol(MappingComponent, Decl(intraExpressionInferences.ts, 100, 2)) +>I : Symbol(I, Decl(intraExpressionInferences.ts, 102, 22)) +>WrappedMap : Symbol(WrappedMap, Decl(intraExpressionInferences.ts, 95, 1)) +>O : Symbol(O, Decl(intraExpressionInferences.ts, 102, 43)) +>WrappedMap : Symbol(WrappedMap, Decl(intraExpressionInferences.ts, 95, 1)) + + setup(): { inputs: I; outputs: O }; +>setup : Symbol(setup, Decl(intraExpressionInferences.ts, 102, 69)) +>inputs : Symbol(inputs, Decl(intraExpressionInferences.ts, 103, 14)) +>I : Symbol(I, Decl(intraExpressionInferences.ts, 102, 22)) +>outputs : Symbol(outputs, Decl(intraExpressionInferences.ts, 103, 25)) +>O : Symbol(O, Decl(intraExpressionInferences.ts, 102, 43)) + + map?: (inputs: Unwrap) => Unwrap; +>map : Symbol(map, Decl(intraExpressionInferences.ts, 103, 39)) +>inputs : Symbol(inputs, Decl(intraExpressionInferences.ts, 104, 11)) +>Unwrap : Symbol(Unwrap, Decl(intraExpressionInferences.ts, 97, 42)) +>I : Symbol(I, Decl(intraExpressionInferences.ts, 102, 22)) +>Unwrap : Symbol(Unwrap, Decl(intraExpressionInferences.ts, 97, 42)) +>O : Symbol(O, Decl(intraExpressionInferences.ts, 102, 43)) + +}; + +declare function createMappingComponent(def: MappingComponent): void; +>createMappingComponent : Symbol(createMappingComponent, Decl(intraExpressionInferences.ts, 105, 2)) +>I : Symbol(I, Decl(intraExpressionInferences.ts, 107, 40)) +>WrappedMap : Symbol(WrappedMap, Decl(intraExpressionInferences.ts, 95, 1)) +>O : Symbol(O, Decl(intraExpressionInferences.ts, 107, 61)) +>WrappedMap : Symbol(WrappedMap, Decl(intraExpressionInferences.ts, 95, 1)) +>def : Symbol(def, Decl(intraExpressionInferences.ts, 107, 84)) +>MappingComponent : Symbol(MappingComponent, Decl(intraExpressionInferences.ts, 100, 2)) +>I : Symbol(I, Decl(intraExpressionInferences.ts, 107, 40)) +>O : Symbol(O, Decl(intraExpressionInferences.ts, 107, 61)) + +createMappingComponent({ +>createMappingComponent : Symbol(createMappingComponent, Decl(intraExpressionInferences.ts, 105, 2)) + + setup() { +>setup : Symbol(setup, Decl(intraExpressionInferences.ts, 109, 24)) + + return { + inputs: { +>inputs : Symbol(inputs, Decl(intraExpressionInferences.ts, 111, 16)) + + num: new Wrapper(), +>num : Symbol(num, Decl(intraExpressionInferences.ts, 112, 21)) +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) + + str: new Wrapper() +>str : Symbol(str, Decl(intraExpressionInferences.ts, 113, 43)) +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) + + }, + outputs: { +>outputs : Symbol(outputs, Decl(intraExpressionInferences.ts, 115, 14)) + + bool: new Wrapper(), +>bool : Symbol(bool, Decl(intraExpressionInferences.ts, 116, 22)) +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) + + str: new Wrapper() +>str : Symbol(str, Decl(intraExpressionInferences.ts, 117, 45)) +>Wrapper : Symbol(Wrapper, Decl(intraExpressionInferences.ts, 89, 3)) + } + }; + }, + map(inputs) { +>map : Symbol(map, Decl(intraExpressionInferences.ts, 121, 6)) +>inputs : Symbol(inputs, Decl(intraExpressionInferences.ts, 122, 8)) + + return { + bool: inputs.nonexistent, +>bool : Symbol(bool, Decl(intraExpressionInferences.ts, 123, 16)) +>inputs : Symbol(inputs, Decl(intraExpressionInferences.ts, 122, 8)) + + str: inputs.num, // Causes error +>str : Symbol(str, Decl(intraExpressionInferences.ts, 124, 37)) +>inputs.num : Symbol(num, Decl(intraExpressionInferences.ts, 112, 21)) +>inputs : Symbol(inputs, Decl(intraExpressionInferences.ts, 122, 8)) +>num : Symbol(num, Decl(intraExpressionInferences.ts, 112, 21)) + } + } +}); + +// Repro from #48279 + +function simplified(props: { generator: () => T, receiver: (t: T) => any }) {} +>simplified : Symbol(simplified, Decl(intraExpressionInferences.ts, 128, 3)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 132, 20)) +>props : Symbol(props, Decl(intraExpressionInferences.ts, 132, 23)) +>generator : Symbol(generator, Decl(intraExpressionInferences.ts, 132, 31)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 132, 20)) +>receiver : Symbol(receiver, Decl(intraExpressionInferences.ts, 132, 51)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 132, 63)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 132, 20)) + +function whatIWant(props: { generator: (bob: any) => T, receiver: (t: T) => any }) {} +>whatIWant : Symbol(whatIWant, Decl(intraExpressionInferences.ts, 132, 81)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 134, 19)) +>props : Symbol(props, Decl(intraExpressionInferences.ts, 134, 22)) +>generator : Symbol(generator, Decl(intraExpressionInferences.ts, 134, 30)) +>bob : Symbol(bob, Decl(intraExpressionInferences.ts, 134, 43)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 134, 19)) +>receiver : Symbol(receiver, Decl(intraExpressionInferences.ts, 134, 58)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 134, 70)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 134, 19)) + +function nonObject(generator: (bob: any) => T, receiver: (t: T) => any) {} +>nonObject : Symbol(nonObject, Decl(intraExpressionInferences.ts, 134, 88)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 136, 19)) +>generator : Symbol(generator, Decl(intraExpressionInferences.ts, 136, 22)) +>bob : Symbol(bob, Decl(intraExpressionInferences.ts, 136, 34)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 136, 19)) +>receiver : Symbol(receiver, Decl(intraExpressionInferences.ts, 136, 49)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 136, 61)) +>T : Symbol(T, Decl(intraExpressionInferences.ts, 136, 19)) + +simplified({ generator: () => 123, receiver: (t) => console.log(t + 2) }) +>simplified : Symbol(simplified, Decl(intraExpressionInferences.ts, 128, 3)) +>generator : Symbol(generator, Decl(intraExpressionInferences.ts, 138, 12)) +>receiver : Symbol(receiver, Decl(intraExpressionInferences.ts, 138, 34)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 138, 46)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 138, 46)) + +whatIWant({ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) }) +>whatIWant : Symbol(whatIWant, Decl(intraExpressionInferences.ts, 132, 81)) +>generator : Symbol(generator, Decl(intraExpressionInferences.ts, 139, 11)) +>bob : Symbol(bob, Decl(intraExpressionInferences.ts, 139, 24)) +>bob : Symbol(bob, Decl(intraExpressionInferences.ts, 139, 24)) +>receiver : Symbol(receiver, Decl(intraExpressionInferences.ts, 139, 44)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 139, 56)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 139, 56)) + +nonObject((bob) => bob ? 1 : 2, (t) => console.log(t + 2)) +>nonObject : Symbol(nonObject, Decl(intraExpressionInferences.ts, 134, 88)) +>bob : Symbol(bob, Decl(intraExpressionInferences.ts, 140, 11)) +>bob : Symbol(bob, Decl(intraExpressionInferences.ts, 140, 11)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 140, 33)) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>t : Symbol(t, Decl(intraExpressionInferences.ts, 140, 33)) + +// Repro from #48466 + +interface Opts { +>Opts : Symbol(Opts, Decl(intraExpressionInferences.ts, 140, 58)) +>TParams : Symbol(TParams, Decl(intraExpressionInferences.ts, 144, 15)) +>TDone : Symbol(TDone, Decl(intraExpressionInferences.ts, 144, 23)) +>TMapped : Symbol(TMapped, Decl(intraExpressionInferences.ts, 144, 30)) + + fetch: (params: TParams, foo: number) => TDone, +>fetch : Symbol(Opts.fetch, Decl(intraExpressionInferences.ts, 144, 41)) +>params : Symbol(params, Decl(intraExpressionInferences.ts, 145, 12)) +>TParams : Symbol(TParams, Decl(intraExpressionInferences.ts, 144, 15)) +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 145, 28)) +>TDone : Symbol(TDone, Decl(intraExpressionInferences.ts, 144, 23)) + + map: (data: TDone) => TMapped +>map : Symbol(Opts.map, Decl(intraExpressionInferences.ts, 145, 51)) +>data : Symbol(data, Decl(intraExpressionInferences.ts, 146, 10)) +>TDone : Symbol(TDone, Decl(intraExpressionInferences.ts, 144, 23)) +>TMapped : Symbol(TMapped, Decl(intraExpressionInferences.ts, 144, 30)) +} + +function example(options: Opts) { +>example : Symbol(example, Decl(intraExpressionInferences.ts, 147, 1)) +>TParams : Symbol(TParams, Decl(intraExpressionInferences.ts, 149, 17)) +>TDone : Symbol(TDone, Decl(intraExpressionInferences.ts, 149, 25)) +>TMapped : Symbol(TMapped, Decl(intraExpressionInferences.ts, 149, 32)) +>options : Symbol(options, Decl(intraExpressionInferences.ts, 149, 42)) +>Opts : Symbol(Opts, Decl(intraExpressionInferences.ts, 140, 58)) +>TParams : Symbol(TParams, Decl(intraExpressionInferences.ts, 149, 17)) +>TDone : Symbol(TDone, Decl(intraExpressionInferences.ts, 149, 25)) +>TMapped : Symbol(TMapped, Decl(intraExpressionInferences.ts, 149, 32)) + + return (params: TParams) => { +>params : Symbol(params, Decl(intraExpressionInferences.ts, 150, 12)) +>TParams : Symbol(TParams, Decl(intraExpressionInferences.ts, 149, 17)) + + const data = options.fetch(params, 123) +>data : Symbol(data, Decl(intraExpressionInferences.ts, 151, 13)) +>options.fetch : Symbol(Opts.fetch, Decl(intraExpressionInferences.ts, 144, 41)) +>options : Symbol(options, Decl(intraExpressionInferences.ts, 149, 42)) +>fetch : Symbol(Opts.fetch, Decl(intraExpressionInferences.ts, 144, 41)) +>params : Symbol(params, Decl(intraExpressionInferences.ts, 150, 12)) + + return options.map(data) +>options.map : Symbol(Opts.map, Decl(intraExpressionInferences.ts, 145, 51)) +>options : Symbol(options, Decl(intraExpressionInferences.ts, 149, 42)) +>map : Symbol(Opts.map, Decl(intraExpressionInferences.ts, 145, 51)) +>data : Symbol(data, Decl(intraExpressionInferences.ts, 151, 13)) + } +} + +interface Params { +>Params : Symbol(Params, Decl(intraExpressionInferences.ts, 154, 1)) + + one: number +>one : Symbol(Params.one, Decl(intraExpressionInferences.ts, 156, 18)) + + two: string +>two : Symbol(Params.two, Decl(intraExpressionInferences.ts, 157, 15)) +} + +example({ +>example : Symbol(example, Decl(intraExpressionInferences.ts, 147, 1)) + + fetch: (params: Params) => 123, +>fetch : Symbol(fetch, Decl(intraExpressionInferences.ts, 161, 9)) +>params : Symbol(params, Decl(intraExpressionInferences.ts, 162, 12)) +>Params : Symbol(Params, Decl(intraExpressionInferences.ts, 154, 1)) + + map: (number) => String(number) +>map : Symbol(map, Decl(intraExpressionInferences.ts, 162, 35)) +>number : Symbol(number, Decl(intraExpressionInferences.ts, 163, 10)) +>String : Symbol(String, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>number : Symbol(number, Decl(intraExpressionInferences.ts, 163, 10)) + +}); + +example({ +>example : Symbol(example, Decl(intraExpressionInferences.ts, 147, 1)) + + fetch: (params: Params, foo: number) => 123, +>fetch : Symbol(fetch, Decl(intraExpressionInferences.ts, 166, 9)) +>params : Symbol(params, Decl(intraExpressionInferences.ts, 167, 12)) +>Params : Symbol(Params, Decl(intraExpressionInferences.ts, 154, 1)) +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 167, 27)) + + map: (number) => String(number) +>map : Symbol(map, Decl(intraExpressionInferences.ts, 167, 48)) +>number : Symbol(number, Decl(intraExpressionInferences.ts, 168, 10)) +>String : Symbol(String, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>number : Symbol(number, Decl(intraExpressionInferences.ts, 168, 10)) + +}); + +example({ +>example : Symbol(example, Decl(intraExpressionInferences.ts, 147, 1)) + + fetch: (params: Params, foo) => 123, +>fetch : Symbol(fetch, Decl(intraExpressionInferences.ts, 171, 9)) +>params : Symbol(params, Decl(intraExpressionInferences.ts, 172, 12)) +>Params : Symbol(Params, Decl(intraExpressionInferences.ts, 154, 1)) +>foo : Symbol(foo, Decl(intraExpressionInferences.ts, 172, 27)) + + map: (number) => String(number) +>map : Symbol(map, Decl(intraExpressionInferences.ts, 172, 40)) +>number : Symbol(number, Decl(intraExpressionInferences.ts, 173, 10)) +>String : Symbol(String, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>number : Symbol(number, Decl(intraExpressionInferences.ts, 173, 10)) + +}); + diff --git a/tests/baselines/reference/intraExpressionInferences.types b/tests/baselines/reference/intraExpressionInferences.types new file mode 100644 index 0000000000000..50a99ac34fe11 --- /dev/null +++ b/tests/baselines/reference/intraExpressionInferences.types @@ -0,0 +1,590 @@ +=== tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts === +// Repros from #47599 + +declare function callIt(obj: { +>callIt : (obj: { produce: (n: number) => T; consume: (x: T) => void; }) => void +>obj : { produce: (n: number) => T; consume: (x: T) => void; } + + produce: (n: number) => T, +>produce : (n: number) => T +>n : number + + consume: (x: T) => void +>consume : (x: T) => void +>x : T + +}): void; + +callIt({ +>callIt({ produce: () => 0, consume: n => n.toFixed()}) : void +>callIt : (obj: { produce: (n: number) => T; consume: (x: T) => void; }) => void +>{ produce: () => 0, consume: n => n.toFixed()} : { produce: () => number; consume: (n: number) => string; } + + produce: () => 0, +>produce : () => number +>() => 0 : () => number +>0 : 0 + + consume: n => n.toFixed() +>consume : (n: number) => string +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +}); + +callIt({ +>callIt({ produce: _a => 0, consume: n => n.toFixed(),}) : void +>callIt : (obj: { produce: (n: number) => T; consume: (x: T) => void; }) => void +>{ produce: _a => 0, consume: n => n.toFixed(),} : { produce: (_a: number) => number; consume: (n: number) => string; } + + produce: _a => 0, +>produce : (_a: number) => number +>_a => 0 : (_a: number) => number +>_a : number +>0 : 0 + + consume: n => n.toFixed(), +>consume : (n: number) => string +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +}); + +callIt({ +>callIt({ produce() { return 0; }, consume: n => n.toFixed()}) : void +>callIt : (obj: { produce: (n: number) => T; consume: (x: T) => void; }) => void +>{ produce() { return 0; }, consume: n => n.toFixed()} : { produce(): number; consume: (n: number) => string; } + + produce() { +>produce : () => number + + return 0; +>0 : 0 + + }, + consume: n => n.toFixed() +>consume : (n: number) => string +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +}); + +declare function callItT(obj: [(n: number) => T, (x: T) => void]): void; +>callItT : (obj: [(n: number) => T, (x: T) => void]) => void +>obj : [(n: number) => T, (x: T) => void] +>n : number +>x : T + +callItT([() => 0, n => n.toFixed()]); +>callItT([() => 0, n => n.toFixed()]) : void +>callItT : (obj: [(n: number) => T, (x: T) => void]) => void +>[() => 0, n => n.toFixed()] : [() => number, (n: number) => string] +>() => 0 : () => number +>0 : 0 +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +callItT([_a => 0, n => n.toFixed()]); +>callItT([_a => 0, n => n.toFixed()]) : void +>callItT : (obj: [(n: number) => T, (x: T) => void]) => void +>[_a => 0, n => n.toFixed()] : [(_a: number) => number, (n: number) => string] +>_a => 0 : (_a: number) => number +>_a : number +>0 : 0 +>n => n.toFixed() : (n: number) => string +>n : number +>n.toFixed() : string +>n.toFixed : (fractionDigits?: number | undefined) => string +>n : number +>toFixed : (fractionDigits?: number | undefined) => string + +// Repro from #25092 + +interface MyInterface { + retrieveGeneric: (parameter: string) => T, +>retrieveGeneric : (parameter: string) => T +>parameter : string + + operateWithGeneric: (generic: T) => string +>operateWithGeneric : (generic: T) => string +>generic : T +} + +const inferTypeFn = (generic: MyInterface) => generic; +>inferTypeFn : (generic: MyInterface) => MyInterface +>(generic: MyInterface) => generic : (generic: MyInterface) => MyInterface +>generic : MyInterface +>generic : MyInterface + +const myGeneric = inferTypeFn({ +>myGeneric : MyInterface +>inferTypeFn({ retrieveGeneric: parameter => 5, operateWithGeneric: generic => generic.toFixed()}) : MyInterface +>inferTypeFn : (generic: MyInterface) => MyInterface +>{ retrieveGeneric: parameter => 5, operateWithGeneric: generic => generic.toFixed()} : { retrieveGeneric: (parameter: string) => number; operateWithGeneric: (generic: number) => string; } + + retrieveGeneric: parameter => 5, +>retrieveGeneric : (parameter: string) => number +>parameter => 5 : (parameter: string) => number +>parameter : string +>5 : 5 + + operateWithGeneric: generic => generic.toFixed() +>operateWithGeneric : (generic: number) => string +>generic => generic.toFixed() : (generic: number) => string +>generic : number +>generic.toFixed() : string +>generic.toFixed : (fractionDigits?: number | undefined) => string +>generic : number +>toFixed : (fractionDigits?: number | undefined) => string + +}); + +// Repro #38623 + +function make(o: { mutations: M, action: (m: M) => void }) { } +>make : (o: { mutations: M; action: (m: M) => void; }) => void +>o : { mutations: M; action: (m: M) => void; } +>mutations : M +>action : (m: M) => void +>m : M + +make({ +>make({ mutations: { foo() { } }, action: (a) => { a.foo() }}) : void +>make : (o: { mutations: M; action: (m: M) => void; }) => void +>{ mutations: { foo() { } }, action: (a) => { a.foo() }} : { mutations: { foo(): void; }; action: (a: { foo(): void; }) => void; } + + mutations: { +>mutations : { foo(): void; } +>{ foo() { } } : { foo(): void; } + + foo() { } +>foo : () => void + + }, + action: (a) => { a.foo() } +>action : (a: { foo(): void; }) => void +>(a) => { a.foo() } : (a: { foo(): void; }) => void +>a : { foo(): void; } +>a.foo() : void +>a.foo : () => void +>a : { foo(): void; } +>foo : () => void + +}); + +// Repro from #38845 + +declare function foo(options: { a: A, b: (a: A) => void }): void; +>foo : (options: { a: A; b: (a: A) => void; }) => void +>options : { a: A; b: (a: A) => void; } +>a : A +>b : (a: A) => void +>a : A + +foo({ +>foo({ a: () => { return 42 }, b(a) {},}) : void +>foo : (options: { a: A; b: (a: A) => void; }) => void +>{ a: () => { return 42 }, b(a) {},} : { a: () => 42; b(a: () => 42): void; } + + a: () => { return 42 }, +>a : () => 42 +>() => { return 42 } : () => 42 +>42 : 42 + + b(a) {}, +>b : (a: () => 42) => void +>a : () => 42 + +}); + +foo({ +>foo({ a: function () { return 42 }, b(a) {},}) : void +>foo : (options: { a: A; b: (a: A) => void; }) => void +>{ a: function () { return 42 }, b(a) {},} : { a: () => 42; b(a: () => 42): void; } + + a: function () { return 42 }, +>a : () => 42 +>function () { return 42 } : () => 42 +>42 : 42 + + b(a) {}, +>b : (a: () => 42) => void +>a : () => 42 + +}); + +foo({ +>foo({ a() { return 42 }, b(a) {},}) : void +>foo : (options: { a: A; b: (a: A) => void; }) => void +>{ a() { return 42 }, b(a) {},} : { a(): 42; b(a: () => 42): void; } + + a() { return 42 }, +>a : () => 42 +>42 : 42 + + b(a) {}, +>b : (a: () => 42) => void +>a : () => 42 + +}); + +// Repro from #38872 + +type Chain = { +>Chain : Chain + + a(): R1, +>a : () => R1 + + b(a: R1): R2; +>b : (a: R1) => R2 +>a : R1 + + c(b: R2): void; +>c : (b: R2) => void +>b : R2 + +}; + +function test(foo: Chain) {} +>test : (foo: Chain) => void +>foo : Chain + +test({ +>test({ a: () => 0, b: (a) => 'a', c: (b) => { const x: string = b; }}) : void +>test : (foo: Chain) => void +>{ a: () => 0, b: (a) => 'a', c: (b) => { const x: string = b; }} : { a: () => number; b: (a: number) => string; c: (b: string) => void; } + + a: () => 0, +>a : () => number +>() => 0 : () => number +>0 : 0 + + b: (a) => 'a', +>b : (a: number) => string +>(a) => 'a' : (a: number) => string +>a : number +>'a' : "a" + + c: (b) => { +>c : (b: string) => void +>(b) => { const x: string = b; } : (b: string) => void +>b : string + + const x: string = b; +>x : string +>b : string + } +}); + +// Repro from #41712 + +class Wrapper { +>Wrapper : Wrapper + + public value?: T; +>value : T | undefined +} + +type WrappedMap = Record; +>WrappedMap : WrappedMap + +type Unwrap = { +>Unwrap : Unwrap + + [K in keyof D]: D[K] extends Wrapper ? T : never; +}; + +type MappingComponent = { +>MappingComponent : MappingComponent + + setup(): { inputs: I; outputs: O }; +>setup : () => { inputs: I; outputs: O;} +>inputs : I +>outputs : O + + map?: (inputs: Unwrap) => Unwrap; +>map : ((inputs: Unwrap) => Unwrap) | undefined +>inputs : Unwrap + +}; + +declare function createMappingComponent(def: MappingComponent): void; +>createMappingComponent : (def: MappingComponent) => void +>def : MappingComponent + +createMappingComponent({ +>createMappingComponent({ setup() { return { inputs: { num: new Wrapper(), str: new Wrapper() }, outputs: { bool: new Wrapper(), str: new Wrapper() } }; }, map(inputs) { return { bool: inputs.nonexistent, str: inputs.num, // Causes error } }}) : void +>createMappingComponent : (def: MappingComponent) => void +>{ setup() { return { inputs: { num: new Wrapper(), str: new Wrapper() }, outputs: { bool: new Wrapper(), str: new Wrapper() } }; }, map(inputs) { return { bool: inputs.nonexistent, str: inputs.num, // Causes error } }} : { setup(): { inputs: { num: Wrapper; str: Wrapper; }; outputs: { bool: Wrapper; str: Wrapper; }; }; map(inputs: Unwrap<{ num: Wrapper; str: Wrapper; }>): { bool: any; str: number; }; } + + setup() { +>setup : () => { inputs: { num: Wrapper; str: Wrapper; }; outputs: { bool: Wrapper; str: Wrapper; }; } + + return { +>{ inputs: { num: new Wrapper(), str: new Wrapper() }, outputs: { bool: new Wrapper(), str: new Wrapper() } } : { inputs: { num: Wrapper; str: Wrapper; }; outputs: { bool: Wrapper; str: Wrapper; }; } + + inputs: { +>inputs : { num: Wrapper; str: Wrapper; } +>{ num: new Wrapper(), str: new Wrapper() } : { num: Wrapper; str: Wrapper; } + + num: new Wrapper(), +>num : Wrapper +>new Wrapper() : Wrapper +>Wrapper : typeof Wrapper + + str: new Wrapper() +>str : Wrapper +>new Wrapper() : Wrapper +>Wrapper : typeof Wrapper + + }, + outputs: { +>outputs : { bool: Wrapper; str: Wrapper; } +>{ bool: new Wrapper(), str: new Wrapper() } : { bool: Wrapper; str: Wrapper; } + + bool: new Wrapper(), +>bool : Wrapper +>new Wrapper() : Wrapper +>Wrapper : typeof Wrapper + + str: new Wrapper() +>str : Wrapper +>new Wrapper() : Wrapper +>Wrapper : typeof Wrapper + } + }; + }, + map(inputs) { +>map : (inputs: Unwrap<{ num: Wrapper; str: Wrapper; }>) => { bool: any; str: number; } +>inputs : Unwrap<{ num: Wrapper; str: Wrapper; }> + + return { +>{ bool: inputs.nonexistent, str: inputs.num, // Causes error } : { bool: any; str: number; } + + bool: inputs.nonexistent, +>bool : any +>inputs.nonexistent : any +>inputs : Unwrap<{ num: Wrapper; str: Wrapper; }> +>nonexistent : any + + str: inputs.num, // Causes error +>str : number +>inputs.num : number +>inputs : Unwrap<{ num: Wrapper; str: Wrapper; }> +>num : number + } + } +}); + +// Repro from #48279 + +function simplified(props: { generator: () => T, receiver: (t: T) => any }) {} +>simplified : (props: { generator: () => T; receiver: (t: T) => any; }) => void +>props : { generator: () => T; receiver: (t: T) => any; } +>generator : () => T +>receiver : (t: T) => any +>t : T + +function whatIWant(props: { generator: (bob: any) => T, receiver: (t: T) => any }) {} +>whatIWant : (props: { generator: (bob: any) => T; receiver: (t: T) => any; }) => void +>props : { generator: (bob: any) => T; receiver: (t: T) => any; } +>generator : (bob: any) => T +>bob : any +>receiver : (t: T) => any +>t : T + +function nonObject(generator: (bob: any) => T, receiver: (t: T) => any) {} +>nonObject : (generator: (bob: any) => T, receiver: (t: T) => any) => void +>generator : (bob: any) => T +>bob : any +>receiver : (t: T) => any +>t : T + +simplified({ generator: () => 123, receiver: (t) => console.log(t + 2) }) +>simplified({ generator: () => 123, receiver: (t) => console.log(t + 2) }) : void +>simplified : (props: { generator: () => T; receiver: (t: T) => any; }) => void +>{ generator: () => 123, receiver: (t) => console.log(t + 2) } : { generator: () => number; receiver: (t: number) => void; } +>generator : () => number +>() => 123 : () => number +>123 : 123 +>receiver : (t: number) => void +>(t) => console.log(t + 2) : (t: number) => void +>t : number +>console.log(t + 2) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>t + 2 : number +>t : number +>2 : 2 + +whatIWant({ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) }) +>whatIWant({ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) }) : void +>whatIWant : (props: { generator: (bob: any) => T; receiver: (t: T) => any; }) => void +>{ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) } : { generator: (bob: any) => 2 | 1; receiver: (t: 2 | 1) => void; } +>generator : (bob: any) => 2 | 1 +>(bob) => bob ? 1 : 2 : (bob: any) => 2 | 1 +>bob : any +>bob ? 1 : 2 : 2 | 1 +>bob : any +>1 : 1 +>2 : 2 +>receiver : (t: 2 | 1) => void +>(t) => console.log(t + 2) : (t: 2 | 1) => void +>t : 2 | 1 +>console.log(t + 2) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>t + 2 : number +>t : 2 | 1 +>2 : 2 + +nonObject((bob) => bob ? 1 : 2, (t) => console.log(t + 2)) +>nonObject((bob) => bob ? 1 : 2, (t) => console.log(t + 2)) : void +>nonObject : (generator: (bob: any) => T, receiver: (t: T) => any) => void +>(bob) => bob ? 1 : 2 : (bob: any) => 2 | 1 +>bob : any +>bob ? 1 : 2 : 2 | 1 +>bob : any +>1 : 1 +>2 : 2 +>(t) => console.log(t + 2) : (t: 2 | 1) => void +>t : 2 | 1 +>console.log(t + 2) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>t + 2 : number +>t : 2 | 1 +>2 : 2 + +// Repro from #48466 + +interface Opts { + fetch: (params: TParams, foo: number) => TDone, +>fetch : (params: TParams, foo: number) => TDone +>params : TParams +>foo : number + + map: (data: TDone) => TMapped +>map : (data: TDone) => TMapped +>data : TDone +} + +function example(options: Opts) { +>example : (options: Opts) => (params: TParams) => TMapped +>options : Opts + + return (params: TParams) => { +>(params: TParams) => { const data = options.fetch(params, 123) return options.map(data) } : (params: TParams) => TMapped +>params : TParams + + const data = options.fetch(params, 123) +>data : TDone +>options.fetch(params, 123) : TDone +>options.fetch : (params: TParams, foo: number) => TDone +>options : Opts +>fetch : (params: TParams, foo: number) => TDone +>params : TParams +>123 : 123 + + return options.map(data) +>options.map(data) : TMapped +>options.map : (data: TDone) => TMapped +>options : Opts +>map : (data: TDone) => TMapped +>data : TDone + } +} + +interface Params { + one: number +>one : number + + two: string +>two : string +} + +example({ +>example({ fetch: (params: Params) => 123, map: (number) => String(number)}) : (params: Params) => string +>example : (options: Opts) => (params: TParams) => TMapped +>{ fetch: (params: Params) => 123, map: (number) => String(number)} : { fetch: (params: Params) => number; map: (number: number) => string; } + + fetch: (params: Params) => 123, +>fetch : (params: Params) => number +>(params: Params) => 123 : (params: Params) => number +>params : Params +>123 : 123 + + map: (number) => String(number) +>map : (number: number) => string +>(number) => String(number) : (number: number) => string +>number : number +>String(number) : string +>String : StringConstructor +>number : number + +}); + +example({ +>example({ fetch: (params: Params, foo: number) => 123, map: (number) => String(number)}) : (params: Params) => string +>example : (options: Opts) => (params: TParams) => TMapped +>{ fetch: (params: Params, foo: number) => 123, map: (number) => String(number)} : { fetch: (params: Params, foo: number) => number; map: (number: number) => string; } + + fetch: (params: Params, foo: number) => 123, +>fetch : (params: Params, foo: number) => number +>(params: Params, foo: number) => 123 : (params: Params, foo: number) => number +>params : Params +>foo : number +>123 : 123 + + map: (number) => String(number) +>map : (number: number) => string +>(number) => String(number) : (number: number) => string +>number : number +>String(number) : string +>String : StringConstructor +>number : number + +}); + +example({ +>example({ fetch: (params: Params, foo) => 123, map: (number) => String(number)}) : (params: Params) => string +>example : (options: Opts) => (params: TParams) => TMapped +>{ fetch: (params: Params, foo) => 123, map: (number) => String(number)} : { fetch: (params: Params, foo: number) => number; map: (number: number) => string; } + + fetch: (params: Params, foo) => 123, +>fetch : (params: Params, foo: number) => number +>(params: Params, foo) => 123 : (params: Params, foo: number) => number +>params : Params +>foo : number +>123 : 123 + + map: (number) => String(number) +>map : (number: number) => string +>(number) => String(number) : (number: number) => string +>number : number +>String(number) : string +>String : StringConstructor +>number : number + +}); + diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts b/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts new file mode 100644 index 0000000000000..5928348c09081 --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/typeInference/intraExpressionInferences.ts @@ -0,0 +1,178 @@ +// @strict: true +// @declaration: true + +// Repros from #47599 + +declare function callIt(obj: { + produce: (n: number) => T, + consume: (x: T) => void +}): void; + +callIt({ + produce: () => 0, + consume: n => n.toFixed() +}); + +callIt({ + produce: _a => 0, + consume: n => n.toFixed(), +}); + +callIt({ + produce() { + return 0; + }, + consume: n => n.toFixed() +}); + +declare function callItT(obj: [(n: number) => T, (x: T) => void]): void; + +callItT([() => 0, n => n.toFixed()]); +callItT([_a => 0, n => n.toFixed()]); + +// Repro from #25092 + +interface MyInterface { + retrieveGeneric: (parameter: string) => T, + operateWithGeneric: (generic: T) => string +} + +const inferTypeFn = (generic: MyInterface) => generic; + +const myGeneric = inferTypeFn({ + retrieveGeneric: parameter => 5, + operateWithGeneric: generic => generic.toFixed() +}); + +// Repro #38623 + +function make(o: { mutations: M, action: (m: M) => void }) { } + +make({ + mutations: { + foo() { } + }, + action: (a) => { a.foo() } +}); + +// Repro from #38845 + +declare function foo(options: { a: A, b: (a: A) => void }): void; + +foo({ + a: () => { return 42 }, + b(a) {}, +}); + +foo({ + a: function () { return 42 }, + b(a) {}, +}); + +foo({ + a() { return 42 }, + b(a) {}, +}); + +// Repro from #38872 + +type Chain = { + a(): R1, + b(a: R1): R2; + c(b: R2): void; +}; + +function test(foo: Chain) {} + +test({ + a: () => 0, + b: (a) => 'a', + c: (b) => { + const x: string = b; + } +}); + +// Repro from #41712 + +class Wrapper { + public value?: T; +} + +type WrappedMap = Record; +type Unwrap = { + [K in keyof D]: D[K] extends Wrapper ? T : never; +}; + +type MappingComponent = { + setup(): { inputs: I; outputs: O }; + map?: (inputs: Unwrap) => Unwrap; +}; + +declare function createMappingComponent(def: MappingComponent): void; + +createMappingComponent({ + setup() { + return { + inputs: { + num: new Wrapper(), + str: new Wrapper() + }, + outputs: { + bool: new Wrapper(), + str: new Wrapper() + } + }; + }, + map(inputs) { + return { + bool: inputs.nonexistent, + str: inputs.num, // Causes error + } + } +}); + +// Repro from #48279 + +function simplified(props: { generator: () => T, receiver: (t: T) => any }) {} + +function whatIWant(props: { generator: (bob: any) => T, receiver: (t: T) => any }) {} + +function nonObject(generator: (bob: any) => T, receiver: (t: T) => any) {} + +simplified({ generator: () => 123, receiver: (t) => console.log(t + 2) }) +whatIWant({ generator: (bob) => bob ? 1 : 2, receiver: (t) => console.log(t + 2) }) +nonObject((bob) => bob ? 1 : 2, (t) => console.log(t + 2)) + +// Repro from #48466 + +interface Opts { + fetch: (params: TParams, foo: number) => TDone, + map: (data: TDone) => TMapped +} + +function example(options: Opts) { + return (params: TParams) => { + const data = options.fetch(params, 123) + return options.map(data) + } +} + +interface Params { + one: number + two: string +} + +example({ + fetch: (params: Params) => 123, + map: (number) => String(number) +}); + +example({ + fetch: (params: Params, foo: number) => 123, + map: (number) => String(number) +}); + +example({ + fetch: (params: Params, foo) => 123, + map: (number) => String(number) +});