From 4d0f706144823cc366dfcd4df366feb8fb83ac68 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Jan 2020 09:23:06 -0800 Subject: [PATCH 1/6] Fix multiple issues with contextually typed parameters --- src/compiler/checker.ts | 116 ++++++++++++++++++---------------------- 1 file changed, 52 insertions(+), 64 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 572993e456058..be261f2feb689 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7059,12 +7059,6 @@ namespace ts { return strictNullChecks && optional ? getOptionalType(type) : type; } - function isParameterOfContextuallyTypedFunction(node: Declaration) { - return node.kind === SyntaxKind.Parameter && - (node.parent.kind === SyntaxKind.FunctionExpression || node.parent.kind === SyntaxKind.ArrowFunction) && - !!getContextualType(node.parent); - } - // Return the inferred type for a variable, parameter, or property declaration function getTypeForVariableLikeDeclaration(declaration: ParameterDeclaration | PropertyDeclaration | PropertySignature | VariableDeclaration | BindingElement, includeOptionality: boolean): Type | undefined { // A variable declared in a for..in statement is of type string, or of type keyof T when the @@ -7136,7 +7130,7 @@ namespace ts { } } // Use contextual parameter type if one is available - const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration, /*forCache*/ true); + const type = declaration.symbol.escapedName === InternalSymbolName.This ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration); if (type) { return addOptionality(type, isOptional); } @@ -7150,7 +7144,7 @@ namespace ts { // Use the type of the initializer expression if one is present and the declaration is // not a parameter of a contextually typed function - if (declaration.initializer && !isParameterOfContextuallyTypedFunction(declaration)) { + if (declaration.initializer) { const type = widenTypeInferredFromInitializer(declaration, checkDeclarationInitializer(declaration)); return addOptionality(type, isOptional); } @@ -7163,7 +7157,7 @@ namespace ts { // If the declaration specifies a binding pattern and is not a parameter of a contextually // typed function, use the type implied by the binding pattern - if (isBindingPattern(declaration.name) && !isParameterOfContextuallyTypedFunction(declaration)) { + if (isBindingPattern(declaration.name)) { return getTypeFromBindingPattern(declaration.name, /*includePatternInType*/ false, /*reportErrors*/ true); } @@ -21161,7 +21155,7 @@ namespace ts { } // Return contextual type of parameter or undefined if no contextual type is available - function getContextuallyTypedParameterType(parameter: ParameterDeclaration, forCache: boolean): Type | undefined { + function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined { const func = parameter.parent; if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) { return undefined; @@ -21184,19 +21178,6 @@ namespace ts { } let contextualSignature = getContextualSignature(func); if (contextualSignature) { - if (forCache) { - // Calling the below guarantees the types are primed and assigned in the same way - // as when the parameter is reached via `checkFunctionExpressionOrObjectLiteralMethod`. - // This should prevent any uninstantiated inference variables in the contextual signature - // from leaking, and should lock in cached parameter types via `assignContextualParameterTypes` - // which we will then immediately use the results of below. - contextuallyCheckFunctionExpressionOrObjectLiteralMethod(func); - const type = getTypeOfSymbol(getMergedSymbol(func.symbol)); - if (isTypeAny(type)) { - return type; - } - contextualSignature = getSignaturesOfType(type, SignatureKind.Call)[0]; - } const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? getRestTypeAtPosition(contextualSignature, index) : @@ -21211,7 +21192,7 @@ namespace ts { } switch (declaration.kind) { case SyntaxKind.Parameter: - return getContextuallyTypedParameterType(declaration, /*forCache*/ false); + return getContextuallyTypedParameterType(declaration); case SyntaxKind.BindingElement: return getContextualTypeForBindingElement(declaration); // By default, do nothing and return undefined - only parameters and binding elements have context implied by a parent @@ -25994,15 +25975,15 @@ namespace ts { if (!parameter) { signature.thisParameter = createSymbolWithType(context.thisParameter, /*type*/ undefined); } - assignTypeToParameterAndFixTypeParameters(signature.thisParameter!, getTypeOfSymbol(context.thisParameter)); + assignParameterType(signature.thisParameter!, getTypeOfSymbol(context.thisParameter)); } } const len = signature.parameters.length - (signatureHasRestParameter(signature) ? 1 : 0); for (let i = 0; i < len; i++) { const parameter = signature.parameters[i]; if (!getEffectiveTypeAnnotationNode(parameter.valueDeclaration)) { - const contextualParameterType = getTypeAtPosition(context, i); - assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType); + const contextualParameterType = tryGetTypeAtPosition(context, i); + assignParameterType(parameter, contextualParameterType); } } if (signatureHasRestParameter(signature)) { @@ -26010,7 +25991,31 @@ namespace ts { const parameter = last(signature.parameters); if (isTransientSymbol(parameter) || !getEffectiveTypeAnnotationNode(parameter.valueDeclaration)) { const contextualParameterType = getRestTypeAtPosition(context, len); - assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType); + assignParameterType(parameter, contextualParameterType); + } + } + } + + function assignNonContextualParameterTypes(signature: Signature) { + if (signature.thisParameter) { + assignParameterType(signature.thisParameter); + } + for (const parameter of signature.parameters) { + assignParameterType(parameter); + } + } + + function assignParameterType(parameter: Symbol, type?: Type) { + const links = getSymbolLinks(parameter); + if (!links.type) { + const declaration = parameter.valueDeclaration as ParameterDeclaration; + links.type = type || getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true); + if (declaration.name.kind !== SyntaxKind.Identifier) { + // if inference didn't come up with anything but unknown, fall back to the binding pattern if present. + if (links.type === unknownType) { + links.type = getTypeFromBindingPattern(declaration.name); + } + assignBindingElementTypes(declaration.name); } } } @@ -26030,21 +26035,6 @@ namespace ts { } } - function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type) { - const links = getSymbolLinks(parameter); - if (!links.type) { - links.type = contextualType; - const decl = parameter.valueDeclaration as ParameterDeclaration; - if (decl.name.kind !== SyntaxKind.Identifier) { - // if inference didn't come up with anything but unknown, fall back to the binding pattern if present. - if (links.type === unknownType) { - links.type = getTypeFromBindingPattern(decl.name); - } - assignBindingElementTypes(decl.name); - } - } - } - function createPromiseType(promisedType: Type): Type { // creates a `Promise` type where `T` is the promisedType argument const globalPromiseType = getGlobalPromiseType(/*reportErrors*/ true); @@ -26430,14 +26420,14 @@ namespace ts { } } - function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, checkMode?: CheckMode): Type { + function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode): Type { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); checkNodeDeferred(node); // The identityMapper object is used to indicate that function expressions are wildcards if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) { // Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage - if (!getEffectiveReturnTypeNode(node) && hasContextSensitiveReturnExpression(node)) { + if (!getEffectiveReturnTypeNode(node) && node.kind === SyntaxKind.ArrowFunction && node.parameters.length === 0) { // Return plain anyFunctionType if there is no possibility we'll make inferences from the return type const contextualSignature = getContextualSignature(node); if (contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature))) { @@ -26461,14 +26451,9 @@ namespace ts { checkGrammarForGenerator(node); } - const type = getTypeOfSymbol(getMergedSymbol(node.symbol)); - if (isTypeAny(type)) { - return type; - } - contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node, checkMode); - return type; + return getTypeOfSymbol(getSymbolOfNode(node)); } function contextuallyCheckFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | ArrowFunction | MethodDeclaration, checkMode?: CheckMode) { @@ -26481,13 +26466,12 @@ namespace ts { // already assigned contextual types. if (!(links.flags & NodeCheckFlags.ContextChecked)) { links.flags |= NodeCheckFlags.ContextChecked; - if (contextualSignature) { - const type = getTypeOfSymbol(getMergedSymbol(node.symbol)); - if (isTypeAny(type)) { - return; - } - const signature = getSignaturesOfType(type, SignatureKind.Call)[0]; - if (isContextSensitive(node)) { + const signature = firstOrUndefined(getSignaturesOfType(getTypeOfSymbol(getSymbolOfNode(node)), SignatureKind.Call)); + if (!signature) { + return; + } + if (isContextSensitive(node)) { + if (contextualSignature) { const inferenceContext = getInferenceContext(node); if (checkMode && checkMode & CheckMode.Inferential) { inferFromAnnotatedParameters(signature, contextualSignature, inferenceContext!); @@ -26496,11 +26480,15 @@ namespace ts { instantiateSignature(contextualSignature, inferenceContext.mapper) : contextualSignature; assignContextualParameterTypes(signature, instantiatedContextualSignature); } - if (!getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) { - const returnType = getReturnTypeFromBody(node, checkMode); - if (!signature.resolvedReturnType) { - signature.resolvedReturnType = returnType; - } + else { + // Force resolution of all parameter types such that the absence of a contextual type is consistently reflected. + assignNonContextualParameterTypes(signature); + } + } + if (contextualSignature && !getReturnTypeFromAnnotation(node) && !signature.resolvedReturnType) { + const returnType = getReturnTypeFromBody(node, checkMode); + if (!signature.resolvedReturnType) { + signature.resolvedReturnType = returnType; } } checkSignatureDeclaration(node); @@ -28209,7 +28197,7 @@ namespace ts { return checkClassExpression(node); case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return checkFunctionExpressionOrObjectLiteralMethod(node, checkMode); + return checkFunctionExpressionOrObjectLiteralMethod(node, checkMode); case SyntaxKind.TypeOfExpression: return checkTypeOfExpression(node); case SyntaxKind.TypeAssertionExpression: From a13cde39a1bf2047afed95504a27399b04962021 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Jan 2020 09:24:11 -0800 Subject: [PATCH 2/6] Accept new baselines --- ...TypedParametersWithInitializers.errors.txt | 42 ------------------- ...extuallyTypedParametersWithInitializers.js | 10 +++-- ...uallyTypedParametersWithInitializers.types | 32 +++++++------- ...ckToBindingPatternForTypeInference.symbols | 1 - .../reference/fatarrowfunctionsErrors.types | 6 +-- .../fatarrowfunctionsOptionalArgs.types | 8 ++-- ...fatarrowfunctionsOptionalArgsErrors4.types | 8 ++-- 7 files changed, 34 insertions(+), 73 deletions(-) delete mode 100644 tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt deleted file mode 100644 index 61bb8b765b61e..0000000000000 --- a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt +++ /dev/null @@ -1,42 +0,0 @@ -tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(8,29): error TS7031: Binding element 'foo' implicitly has an 'any' type. -tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(14,27): error TS7006: Parameter 'foo' implicitly has an 'any' type. -tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(27,42): error TS7031: Binding element 'foo' implicitly has an 'any' type. - - -==== tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts (3 errors) ==== - declare function id1(input: T): T; - declare function id2 any>(input: T): T; - declare function id3 any>(input: T): T; - declare function id4 any>(input: T): T; - declare function id5 any>(input: T): T; - - const f10 = function ({ foo = 42 }) { return foo }; - const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error - ~~~ -!!! error TS7031: Binding element 'foo' implicitly has an 'any' type. - const f12 = id2(function ({ foo = 42 }) { return foo }); - const f13 = id3(function ({ foo = 42 }) { return foo }); - const f14 = id4(function ({ foo = 42 }) { return foo }); - - const f20 = function (foo = 42) { return foo }; - const f21 = id1(function (foo = 42) { return foo }); // Implicit any error - ~~~~~~~~ -!!! error TS7006: Parameter 'foo' implicitly has an 'any' type. - const f22 = id2(function (foo = 42) { return foo }); - const f25 = id5(function (foo = 42) { return foo }); - - // Repro from #28816 - - function id(input: T): T { return input } - - function getFoo ({ foo = 42 }) { - return foo; - } - - const newGetFoo = id(getFoo); - const newGetFoo2 = id(function getFoo ({ foo = 42 }) { - ~~~ -!!! error TS7031: Binding element 'foo' implicitly has an 'any' type. - return foo; - }); - \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js index 96b55c431572e..d0ca988ba9aed 100644 --- a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js +++ b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js @@ -94,7 +94,9 @@ declare function id5 any>(input: T): T; declare const f10: ({ foo }: { foo?: number | undefined; }) => number; -declare const f11: ({ foo }: any) => any; +declare const f11: ({ foo }: { + foo?: number | undefined; +}) => number; declare const f12: ({ foo }: any) => any; declare const f13: ({ foo }: { foo: any; @@ -103,7 +105,7 @@ declare const f14: ({ foo }: { foo?: number | undefined; }) => number; declare const f20: (foo?: number) => number; -declare const f21: (foo?: any) => any; +declare const f21: (foo?: number) => number; declare const f22: (foo?: any) => any; declare const f25: (foo?: number | undefined) => number; declare function id(input: T): T; @@ -111,4 +113,6 @@ declare function getFoo({ foo }: { foo?: number | undefined; }): number; declare const newGetFoo: typeof getFoo; -declare const newGetFoo2: ({ foo }: any) => any; +declare const newGetFoo2: ({ foo }: { + foo?: number | undefined; +}) => number; diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types index 3824b16ae62b4..9c24227e45979 100644 --- a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types +++ b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types @@ -33,13 +33,13 @@ const f10 = function ({ foo = 42 }) { return foo }; >foo : number const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error ->f11 : ({ foo }: any) => any ->id1(function ({ foo = 42 }) { return foo }) : ({ foo }: any) => any +>f11 : ({ foo }: { foo?: number | undefined; }) => number +>id1(function ({ foo = 42 }) { return foo }) : ({ foo }: { foo?: number | undefined; }) => number >id1 : (input: T) => T ->function ({ foo = 42 }) { return foo } : ({ foo }: any) => any ->foo : any +>function ({ foo = 42 }) { return foo } : ({ foo }: { foo?: number | undefined; }) => number +>foo : number >42 : 42 ->foo : any +>foo : number const f12 = id2(function ({ foo = 42 }) { return foo }); >f12 : ({ foo }: any) => any @@ -76,13 +76,13 @@ const f20 = function (foo = 42) { return foo }; >foo : number const f21 = id1(function (foo = 42) { return foo }); // Implicit any error ->f21 : (foo?: any) => any ->id1(function (foo = 42) { return foo }) : (foo?: any) => any +>f21 : (foo?: number) => number +>id1(function (foo = 42) { return foo }) : (foo?: number) => number >id1 : (input: T) => T ->function (foo = 42) { return foo } : (foo?: any) => any ->foo : any +>function (foo = 42) { return foo } : (foo?: number) => number +>foo : number >42 : 42 ->foo : any +>foo : number const f22 = id2(function (foo = 42) { return foo }); >f22 : (foo?: any) => any @@ -125,16 +125,16 @@ const newGetFoo = id(getFoo); >getFoo : ({ foo }: { foo?: number | undefined; }) => number const newGetFoo2 = id(function getFoo ({ foo = 42 }) { ->newGetFoo2 : ({ foo }: any) => any ->id(function getFoo ({ foo = 42 }) { return foo;}) : ({ foo }: any) => any +>newGetFoo2 : ({ foo }: { foo?: number | undefined; }) => number +>id(function getFoo ({ foo = 42 }) { return foo;}) : ({ foo }: { foo?: number | undefined; }) => number >id : (input: T) => T ->function getFoo ({ foo = 42 }) { return foo;} : ({ foo }: any) => any ->getFoo : ({ foo }: any) => any ->foo : any +>function getFoo ({ foo = 42 }) { return foo;} : ({ foo }: { foo?: number | undefined; }) => number +>getFoo : ({ foo }: { foo?: number | undefined; }) => number +>foo : number >42 : 42 return foo; ->foo : any +>foo : number }); diff --git a/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols b/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols index 4f450e21c24c0..f57b234f39fbc 100644 --- a/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols +++ b/tests/baselines/reference/fallbackToBindingPatternForTypeInference.symbols @@ -18,7 +18,6 @@ trans(([b,c]) => 'foo'); trans(({d: [e,f]}) => 'foo'); >trans : Symbol(trans, Decl(fallbackToBindingPatternForTypeInference.ts, 0, 0)) ->d : Symbol(d) >e : Symbol(e, Decl(fallbackToBindingPatternForTypeInference.ts, 3, 12)) >f : Symbol(f, Decl(fallbackToBindingPatternForTypeInference.ts, 3, 14)) diff --git a/tests/baselines/reference/fatarrowfunctionsErrors.types b/tests/baselines/reference/fatarrowfunctionsErrors.types index 36b123e338af3..4a493734e09aa 100644 --- a/tests/baselines/reference/fatarrowfunctionsErrors.types +++ b/tests/baselines/reference/fatarrowfunctionsErrors.types @@ -25,10 +25,10 @@ foo((x?)=>{return x;}) foo((x=0)=>{return x;}) >foo((x=0)=>{return x;}) : any >foo : any ->(x=0)=>{return x;} : (x?: any) => any ->x : any +>(x=0)=>{return x;} : (x?: number) => number +>x : number >0 : 0 ->x : any +>x : number var y = x:number => x*x; >y : any diff --git a/tests/baselines/reference/fatarrowfunctionsOptionalArgs.types b/tests/baselines/reference/fatarrowfunctionsOptionalArgs.types index ed7438dd6a057..e9ae9488b91cd 100644 --- a/tests/baselines/reference/fatarrowfunctionsOptionalArgs.types +++ b/tests/baselines/reference/fatarrowfunctionsOptionalArgs.types @@ -653,8 +653,8 @@ foo( >116 : 116 (a = 0) => 117, ->(a = 0) => 117 : (a?: any) => number ->a : any +>(a = 0) => 117 : (a?: number) => number +>a : number >0 : 0 >117 : 117 @@ -670,9 +670,9 @@ foo( >119 : 119 (a, b? = 0, ...c: number[]) => 120, ->(a, b? = 0, ...c: number[]) => 120 : (a: any, b?: any, ...c: number[]) => number +>(a, b? = 0, ...c: number[]) => 120 : (a: any, b?: number, ...c: number[]) => number >a : any ->b : any +>b : number >0 : 0 >c : number[] >120 : 120 diff --git a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors4.types b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors4.types index 7496677a194b0..18860e274ca20 100644 --- a/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors4.types +++ b/tests/baselines/reference/fatarrowfunctionsOptionalArgsErrors4.types @@ -88,8 +88,8 @@ >116 : 116 (a = 0) => 117, ->(a = 0) => 117 : (a?: any) => number ->a : any +>(a = 0) => 117 : (a?: number) => number +>a : number >0 : 0 >117 : 117 @@ -105,9 +105,9 @@ >119 : 119 (a, b? = 0, ...c: number[]) => 120, ->(a, b? = 0, ...c: number[]) => 120 : (a: any, b?: any, ...c: number[]) => number +>(a, b? = 0, ...c: number[]) => 120 : (a: any, b?: number, ...c: number[]) => number >a : any ->b : any +>b : number >0 : 0 >c : number[] >120 : 120 From d828b2b4fae5c5e8908c88e0b3ba0be938d80c17 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Jan 2020 09:46:55 -0800 Subject: [PATCH 3/6] Fix lint error --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index be261f2feb689..26c92707eb8fe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21176,7 +21176,7 @@ namespace ts { links.resolvedSignature = cached; return type; } - let contextualSignature = getContextualSignature(func); + const contextualSignature = getContextualSignature(func); if (contextualSignature) { const index = func.parameters.indexOf(parameter) - (getThisParameter(func) ? 1 : 0); return parameter.dotDotDotToken && lastOrUndefined(func.parameters) === parameter ? From 694f9e53a9b9fe5f919077770f9c8c8011d4015a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 28 Jan 2020 09:47:05 -0800 Subject: [PATCH 4/6] Add tests --- ...TypedParametersWithInitializers.errors.txt | 93 +++++++ ...extuallyTypedParametersWithInitializers.js | 193 +++++++++++--- ...llyTypedParametersWithInitializers.symbols | 229 +++++++++++++++-- ...uallyTypedParametersWithInitializers.types | 241 +++++++++++++++++- ...extuallyTypedParametersWithInitializers.ts | 58 ++++- 5 files changed, 753 insertions(+), 61 deletions(-) create mode 100644 tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt new file mode 100644 index 0000000000000..680ee7d4772ac --- /dev/null +++ b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt @@ -0,0 +1,93 @@ +tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(24,24): error TS7006: Parameter 'x' implicitly has an 'any' type. +tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(40,5): error TS7006: Parameter 'x' implicitly has an 'any' type. + + +==== tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts (2 errors) ==== + declare function id1(input: T): T; + declare function id2 any>(input: T): T; + declare function id3 any>(input: T): T; + declare function id4 any>(input: T): T; + declare function id5 any>(input: T): T; + + const f10 = function ({ foo = 42 }) { return foo }; + const f11 = id1(function ({ foo = 42 }) { return foo }); + const f12 = id2(function ({ foo = 42 }) { return foo }); + const f13 = id3(function ({ foo = 42 }) { return foo }); + const f14 = id4(function ({ foo = 42 }) { return foo }); + + const f20 = function (foo = 42) { return foo }; + const f21 = id1(function (foo = 42) { return foo }); + const f22 = id2(function (foo = 42) { return foo }); + const f25 = id5(function (foo = 42) { return foo }); + + const f1 = (x = 1) => 0; // number + const f2: any = (x = 1) => 0; // number + const f3: unknown = (x = 1) => 0; // number + const f4: Function = (x = 1) => 0; // number + const f5: (...args: any[]) => any = (x = 1) => 0; // any + const f6: () => any = (x = 1) => 0; // number + const f7: () => any = (x?) => 0; // Implicit any error + ~~ +!!! error TS7006: Parameter 'x' implicitly has an 'any' type. + const f8: () => any = (...x) => 0; // [] + + declare function g1(x: T): T; + declare function g2(x: T): T; + declare function g3(x: T): T; + declare function g4(x: T): T; + declare function g5 any>(x: T): T; + declare function g6 any>(x: T): T; + + g1((x = 1) => 0); // number + g2((x = 1) => 0); // number + g3((x = 1) => 0); // number + g4((x = 1) => 0); // number + g5((x = 1) => 0); // any + g6((x = 1) => 0); // number + g6((x?) => 0); // Implicit any error + ~~ +!!! error TS7006: Parameter 'x' implicitly has an 'any' type. + g6((...x) => 0); // [] + + // Repro from #28816 + + function id(input: T): T { return input } + + function getFoo ({ foo = 42 }) { + return foo; + } + + const newGetFoo = id(getFoo); + const newGetFoo2 = id(function getFoo ({ foo = 42 }) { + return foo; + }); + + // Repro from comment in #30840 + + declare function memoize(func: F): F; + + function add(x: number, y = 0): number { + return x + y; + } + const memoizedAdd = memoize(add); + + const add2 = (x: number, y = 0): number => x + y; + const memoizedAdd2 = memoize(add2); + + const memoizedAdd3 = memoize((x: number, y = 0): number => x + y); + + // Repro from #36052 + + declare function execute(script: string | Function): Promise; + + export function executeSomething() { + return execute((root: HTMLElement, debug = true) => { + if (debug) { + root.innerHTML = ''; + } + }); + } + + const fz1 = (debug = true) => false; + const fz2: Function = (debug = true) => false; + \ No newline at end of file diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js index d0ca988ba9aed..b37ae8bfaa1e8 100644 --- a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js +++ b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.js @@ -6,16 +6,41 @@ declare function id4 any>(input: T): T; declare function id5 any>(input: T): T; const f10 = function ({ foo = 42 }) { return foo }; -const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error +const f11 = id1(function ({ foo = 42 }) { return foo }); const f12 = id2(function ({ foo = 42 }) { return foo }); const f13 = id3(function ({ foo = 42 }) { return foo }); const f14 = id4(function ({ foo = 42 }) { return foo }); const f20 = function (foo = 42) { return foo }; -const f21 = id1(function (foo = 42) { return foo }); // Implicit any error +const f21 = id1(function (foo = 42) { return foo }); const f22 = id2(function (foo = 42) { return foo }); const f25 = id5(function (foo = 42) { return foo }); +const f1 = (x = 1) => 0; // number +const f2: any = (x = 1) => 0; // number +const f3: unknown = (x = 1) => 0; // number +const f4: Function = (x = 1) => 0; // number +const f5: (...args: any[]) => any = (x = 1) => 0; // any +const f6: () => any = (x = 1) => 0; // number +const f7: () => any = (x?) => 0; // Implicit any error +const f8: () => any = (...x) => 0; // [] + +declare function g1(x: T): T; +declare function g2(x: T): T; +declare function g3(x: T): T; +declare function g4(x: T): T; +declare function g5 any>(x: T): T; +declare function g6 any>(x: T): T; + +g1((x = 1) => 0); // number +g2((x = 1) => 0); // number +g3((x = 1) => 0); // number +g4((x = 1) => 0); // number +g5((x = 1) => 0); // any +g6((x = 1) => 0); // number +g6((x?) => 0); // Implicit any error +g6((...x) => 0); // [] + // Repro from #28816 function id(input: T): T { return input } @@ -28,10 +53,40 @@ const newGetFoo = id(getFoo); const newGetFoo2 = id(function getFoo ({ foo = 42 }) { return foo; }); + +// Repro from comment in #30840 + +declare function memoize(func: F): F; + +function add(x: number, y = 0): number { + return x + y; +} +const memoizedAdd = memoize(add); + +const add2 = (x: number, y = 0): number => x + y; +const memoizedAdd2 = memoize(add2); + +const memoizedAdd3 = memoize((x: number, y = 0): number => x + y); + +// Repro from #36052 + +declare function execute(script: string | Function): Promise; + +export function executeSomething() { + return execute((root: HTMLElement, debug = true) => { + if (debug) { + root.innerHTML = ''; + } + }); +} + +const fz1 = (debug = true) => false; +const fz2: Function = (debug = true) => false; //// [contextuallyTypedParametersWithInitializers.js] "use strict"; +exports.__esModule = true; var f10 = function (_a) { var _b = _a.foo, foo = _b === void 0 ? 42 : _b; return foo; @@ -39,7 +94,7 @@ var f10 = function (_a) { var f11 = id1(function (_a) { var _b = _a.foo, foo = _b === void 0 ? 42 : _b; return foo; -}); // Implicit any error +}); var f12 = id2(function (_a) { var _b = _a.foo, foo = _b === void 0 ? 42 : _b; return foo; @@ -59,7 +114,7 @@ var f20 = function (foo) { var f21 = id1(function (foo) { if (foo === void 0) { foo = 42; } return foo; -}); // Implicit any error +}); var f22 = id2(function (foo) { if (foo === void 0) { foo = 42; } return foo; @@ -68,6 +123,70 @@ var f25 = id5(function (foo) { if (foo === void 0) { foo = 42; } return foo; }); +var f1 = function (x) { + if (x === void 0) { x = 1; } + return 0; +}; // number +var f2 = function (x) { + if (x === void 0) { x = 1; } + return 0; +}; // number +var f3 = function (x) { + if (x === void 0) { x = 1; } + return 0; +}; // number +var f4 = function (x) { + if (x === void 0) { x = 1; } + return 0; +}; // number +var f5 = function (x) { + if (x === void 0) { x = 1; } + return 0; +}; // any +var f6 = function (x) { + if (x === void 0) { x = 1; } + return 0; +}; // number +var f7 = function (x) { return 0; }; // Implicit any error +var f8 = function () { + var x = []; + for (var _i = 0; _i < arguments.length; _i++) { + x[_i] = arguments[_i]; + } + return 0; +}; // [] +g1(function (x) { + if (x === void 0) { x = 1; } + return 0; +}); // number +g2(function (x) { + if (x === void 0) { x = 1; } + return 0; +}); // number +g3(function (x) { + if (x === void 0) { x = 1; } + return 0; +}); // number +g4(function (x) { + if (x === void 0) { x = 1; } + return 0; +}); // number +g5(function (x) { + if (x === void 0) { x = 1; } + return 0; +}); // any +g6(function (x) { + if (x === void 0) { x = 1; } + return 0; +}); // number +g6(function (x) { return 0; }); // Implicit any error +g6(function () { + var x = []; + for (var _i = 0; _i < arguments.length; _i++) { + x[_i] = arguments[_i]; + } + return 0; +}); // [] // Repro from #28816 function id(input) { return input; } function getFoo(_a) { @@ -79,40 +198,38 @@ var newGetFoo2 = id(function getFoo(_a) { var _b = _a.foo, foo = _b === void 0 ? 42 : _b; return foo; }); +function add(x, y) { + if (y === void 0) { y = 0; } + return x + y; +} +var memoizedAdd = memoize(add); +var add2 = function (x, y) { + if (y === void 0) { y = 0; } + return x + y; +}; +var memoizedAdd2 = memoize(add2); +var memoizedAdd3 = memoize(function (x, y) { + if (y === void 0) { y = 0; } + return x + y; +}); +function executeSomething() { + return execute(function (root, debug) { + if (debug === void 0) { debug = true; } + if (debug) { + root.innerHTML = ''; + } + }); +} +exports.executeSomething = executeSomething; +var fz1 = function (debug) { + if (debug === void 0) { debug = true; } + return false; +}; +var fz2 = function (debug) { + if (debug === void 0) { debug = true; } + return false; +}; //// [contextuallyTypedParametersWithInitializers.d.ts] -declare function id1(input: T): T; -declare function id2 any>(input: T): T; -declare function id3 any>(input: T): T; -declare function id4 any>(input: T): T; -declare function id5 any>(input: T): T; -declare const f10: ({ foo }: { - foo?: number | undefined; -}) => number; -declare const f11: ({ foo }: { - foo?: number | undefined; -}) => number; -declare const f12: ({ foo }: any) => any; -declare const f13: ({ foo }: { - foo: any; -}) => any; -declare const f14: ({ foo }: { - foo?: number | undefined; -}) => number; -declare const f20: (foo?: number) => number; -declare const f21: (foo?: number) => number; -declare const f22: (foo?: any) => any; -declare const f25: (foo?: number | undefined) => number; -declare function id(input: T): T; -declare function getFoo({ foo }: { - foo?: number | undefined; -}): number; -declare const newGetFoo: typeof getFoo; -declare const newGetFoo2: ({ foo }: { - foo?: number | undefined; -}) => number; +export declare function executeSomething(): Promise; diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.symbols b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.symbols index 6932f7b0cb8fc..1b4e7c47528fb 100644 --- a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.symbols +++ b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.symbols @@ -45,7 +45,7 @@ const f10 = function ({ foo = 42 }) { return foo }; >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 6, 23)) >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 6, 23)) -const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error +const f11 = id1(function ({ foo = 42 }) { return foo }); >f11 : Symbol(f11, Decl(contextuallyTypedParametersWithInitializers.ts, 7, 5)) >id1 : Symbol(id1, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 0)) >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 7, 27)) @@ -74,7 +74,7 @@ const f20 = function (foo = 42) { return foo }; >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 12, 22)) >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 12, 22)) -const f21 = id1(function (foo = 42) { return foo }); // Implicit any error +const f21 = id1(function (foo = 42) { return foo }); >f21 : Symbol(f21, Decl(contextuallyTypedParametersWithInitializers.ts, 13, 5)) >id1 : Symbol(id1, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 0)) >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 13, 26)) @@ -92,37 +92,228 @@ const f25 = id5(function (foo = 42) { return foo }); >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 26)) >foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 26)) +const f1 = (x = 1) => 0; // number +>f1 : Symbol(f1, Decl(contextuallyTypedParametersWithInitializers.ts, 17, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 17, 12)) + +const f2: any = (x = 1) => 0; // number +>f2 : Symbol(f2, Decl(contextuallyTypedParametersWithInitializers.ts, 18, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 18, 17)) + +const f3: unknown = (x = 1) => 0; // number +>f3 : Symbol(f3, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 21)) + +const f4: Function = (x = 1) => 0; // number +>f4 : Symbol(f4, Decl(contextuallyTypedParametersWithInitializers.ts, 20, 5)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 20, 22)) + +const f5: (...args: any[]) => any = (x = 1) => 0; // any +>f5 : Symbol(f5, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 5)) +>args : Symbol(args, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 11)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 37)) + +const f6: () => any = (x = 1) => 0; // number +>f6 : Symbol(f6, Decl(contextuallyTypedParametersWithInitializers.ts, 22, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 22, 23)) + +const f7: () => any = (x?) => 0; // Implicit any error +>f7 : Symbol(f7, Decl(contextuallyTypedParametersWithInitializers.ts, 23, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 23, 23)) + +const f8: () => any = (...x) => 0; // [] +>f8 : Symbol(f8, Decl(contextuallyTypedParametersWithInitializers.ts, 24, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 24, 23)) + +declare function g1(x: T): T; +>g1 : Symbol(g1, Decl(contextuallyTypedParametersWithInitializers.ts, 24, 34)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 20)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 23)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 20)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 20)) + +declare function g2(x: T): T; +>g2 : Symbol(g2, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 32)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 27, 20)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 27, 35)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 27, 20)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 27, 20)) + +declare function g3(x: T): T; +>g3 : Symbol(g3, Decl(contextuallyTypedParametersWithInitializers.ts, 27, 44)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 28, 20)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 28, 39)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 28, 20)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 28, 20)) + +declare function g4(x: T): T; +>g4 : Symbol(g4, Decl(contextuallyTypedParametersWithInitializers.ts, 28, 48)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 29, 20)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 29, 40)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 29, 20)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 29, 20)) + +declare function g5 any>(x: T): T; +>g5 : Symbol(g5, Decl(contextuallyTypedParametersWithInitializers.ts, 29, 49)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 20)) +>args : Symbol(args, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 31)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 55)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 20)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 20)) + +declare function g6 any>(x: T): T; +>g6 : Symbol(g6, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 64)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 31, 20)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 31, 41)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 31, 20)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 31, 20)) + +g1((x = 1) => 0); // number +>g1 : Symbol(g1, Decl(contextuallyTypedParametersWithInitializers.ts, 24, 34)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 33, 4)) + +g2((x = 1) => 0); // number +>g2 : Symbol(g2, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 32)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 34, 4)) + +g3((x = 1) => 0); // number +>g3 : Symbol(g3, Decl(contextuallyTypedParametersWithInitializers.ts, 27, 44)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 35, 4)) + +g4((x = 1) => 0); // number +>g4 : Symbol(g4, Decl(contextuallyTypedParametersWithInitializers.ts, 28, 48)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 36, 4)) + +g5((x = 1) => 0); // any +>g5 : Symbol(g5, Decl(contextuallyTypedParametersWithInitializers.ts, 29, 49)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 37, 4)) + +g6((x = 1) => 0); // number +>g6 : Symbol(g6, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 64)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 38, 4)) + +g6((x?) => 0); // Implicit any error +>g6 : Symbol(g6, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 64)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 39, 4)) + +g6((...x) => 0); // [] +>g6 : Symbol(g6, Decl(contextuallyTypedParametersWithInitializers.ts, 30, 64)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 40, 4)) + // Repro from #28816 function id(input: T): T { return input } ->id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 52)) ->T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 12)) ->input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 15)) ->T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 12)) ->T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 12)) ->input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 15)) +>id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 40, 16)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 12)) +>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 15)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 12)) +>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 12)) +>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 15)) function getFoo ({ foo = 42 }) { ->getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 44)) ->foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 18)) +>getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 44)) +>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 46, 18)) return foo; ->foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 18)) +>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 46, 18)) } const newGetFoo = id(getFoo); ->newGetFoo : Symbol(newGetFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 25, 5)) ->id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 52)) ->getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 44)) +>newGetFoo : Symbol(newGetFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 50, 5)) +>id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 40, 16)) +>getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 44, 44)) const newGetFoo2 = id(function getFoo ({ foo = 42 }) { ->newGetFoo2 : Symbol(newGetFoo2, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 5)) ->id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 52)) ->getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 22)) ->foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 40)) +>newGetFoo2 : Symbol(newGetFoo2, Decl(contextuallyTypedParametersWithInitializers.ts, 51, 5)) +>id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 40, 16)) +>getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 51, 22)) +>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 51, 40)) return foo; ->foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 40)) +>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 51, 40)) }); +// Repro from comment in #30840 + +declare function memoize(func: F): F; +>memoize : Symbol(memoize, Decl(contextuallyTypedParametersWithInitializers.ts, 53, 3)) +>F : Symbol(F, Decl(contextuallyTypedParametersWithInitializers.ts, 57, 25)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>func : Symbol(func, Decl(contextuallyTypedParametersWithInitializers.ts, 57, 45)) +>F : Symbol(F, Decl(contextuallyTypedParametersWithInitializers.ts, 57, 25)) +>F : Symbol(F, Decl(contextuallyTypedParametersWithInitializers.ts, 57, 25)) + +function add(x: number, y = 0): number { +>add : Symbol(add, Decl(contextuallyTypedParametersWithInitializers.ts, 57, 57)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 59, 13)) +>y : Symbol(y, Decl(contextuallyTypedParametersWithInitializers.ts, 59, 23)) + + return x + y; +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 59, 13)) +>y : Symbol(y, Decl(contextuallyTypedParametersWithInitializers.ts, 59, 23)) +} +const memoizedAdd = memoize(add); +>memoizedAdd : Symbol(memoizedAdd, Decl(contextuallyTypedParametersWithInitializers.ts, 62, 5)) +>memoize : Symbol(memoize, Decl(contextuallyTypedParametersWithInitializers.ts, 53, 3)) +>add : Symbol(add, Decl(contextuallyTypedParametersWithInitializers.ts, 57, 57)) + +const add2 = (x: number, y = 0): number => x + y; +>add2 : Symbol(add2, Decl(contextuallyTypedParametersWithInitializers.ts, 64, 5)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 64, 14)) +>y : Symbol(y, Decl(contextuallyTypedParametersWithInitializers.ts, 64, 24)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 64, 14)) +>y : Symbol(y, Decl(contextuallyTypedParametersWithInitializers.ts, 64, 24)) + +const memoizedAdd2 = memoize(add2); +>memoizedAdd2 : Symbol(memoizedAdd2, Decl(contextuallyTypedParametersWithInitializers.ts, 65, 5)) +>memoize : Symbol(memoize, Decl(contextuallyTypedParametersWithInitializers.ts, 53, 3)) +>add2 : Symbol(add2, Decl(contextuallyTypedParametersWithInitializers.ts, 64, 5)) + +const memoizedAdd3 = memoize((x: number, y = 0): number => x + y); +>memoizedAdd3 : Symbol(memoizedAdd3, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 5)) +>memoize : Symbol(memoize, Decl(contextuallyTypedParametersWithInitializers.ts, 53, 3)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 30)) +>y : Symbol(y, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 40)) +>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 30)) +>y : Symbol(y, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 40)) + +// Repro from #36052 + +declare function execute(script: string | Function): Promise; +>execute : Symbol(execute, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 66)) +>script : Symbol(script, Decl(contextuallyTypedParametersWithInitializers.ts, 71, 25)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --)) + +export function executeSomething() { +>executeSomething : Symbol(executeSomething, Decl(contextuallyTypedParametersWithInitializers.ts, 71, 69)) + + return execute((root: HTMLElement, debug = true) => { +>execute : Symbol(execute, Decl(contextuallyTypedParametersWithInitializers.ts, 67, 66)) +>root : Symbol(root, Decl(contextuallyTypedParametersWithInitializers.ts, 74, 20)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>debug : Symbol(debug, Decl(contextuallyTypedParametersWithInitializers.ts, 74, 38)) + + if (debug) { +>debug : Symbol(debug, Decl(contextuallyTypedParametersWithInitializers.ts, 74, 38)) + + root.innerHTML = ''; +>root.innerHTML : Symbol(InnerHTML.innerHTML, Decl(lib.dom.d.ts, --, --)) +>root : Symbol(root, Decl(contextuallyTypedParametersWithInitializers.ts, 74, 20)) +>innerHTML : Symbol(InnerHTML.innerHTML, Decl(lib.dom.d.ts, --, --)) + } + }); +} + +const fz1 = (debug = true) => false; +>fz1 : Symbol(fz1, Decl(contextuallyTypedParametersWithInitializers.ts, 81, 5)) +>debug : Symbol(debug, Decl(contextuallyTypedParametersWithInitializers.ts, 81, 13)) + +const fz2: Function = (debug = true) => false; +>fz2 : Symbol(fz2, Decl(contextuallyTypedParametersWithInitializers.ts, 82, 5)) +>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>debug : Symbol(debug, Decl(contextuallyTypedParametersWithInitializers.ts, 82, 23)) + diff --git a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types index 9c24227e45979..7be0d89aedcff 100644 --- a/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types +++ b/tests/baselines/reference/contextuallyTypedParametersWithInitializers.types @@ -32,7 +32,7 @@ const f10 = function ({ foo = 42 }) { return foo }; >42 : 42 >foo : number -const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error +const f11 = id1(function ({ foo = 42 }) { return foo }); >f11 : ({ foo }: { foo?: number | undefined; }) => number >id1(function ({ foo = 42 }) { return foo }) : ({ foo }: { foo?: number | undefined; }) => number >id1 : (input: T) => T @@ -75,7 +75,7 @@ const f20 = function (foo = 42) { return foo }; >42 : 42 >foo : number -const f21 = id1(function (foo = 42) { return foo }); // Implicit any error +const f21 = id1(function (foo = 42) { return foo }); >f21 : (foo?: number) => number >id1(function (foo = 42) { return foo }) : (foo?: number) => number >id1 : (input: T) => T @@ -102,6 +102,148 @@ const f25 = id5(function (foo = 42) { return foo }); >42 : 42 >foo : number +const f1 = (x = 1) => 0; // number +>f1 : (x?: number) => number +>(x = 1) => 0 : (x?: number) => number +>x : number +>1 : 1 +>0 : 0 + +const f2: any = (x = 1) => 0; // number +>f2 : any +>(x = 1) => 0 : (x?: number) => number +>x : number +>1 : 1 +>0 : 0 + +const f3: unknown = (x = 1) => 0; // number +>f3 : unknown +>(x = 1) => 0 : (x?: number) => number +>x : number +>1 : 1 +>0 : 0 + +const f4: Function = (x = 1) => 0; // number +>f4 : Function +>(x = 1) => 0 : (x?: number) => number +>x : number +>1 : 1 +>0 : 0 + +const f5: (...args: any[]) => any = (x = 1) => 0; // any +>f5 : (...args: any[]) => any +>args : any[] +>(x = 1) => 0 : (x?: any) => number +>x : any +>1 : 1 +>0 : 0 + +const f6: () => any = (x = 1) => 0; // number +>f6 : () => any +>(x = 1) => 0 : (x?: number) => number +>x : number +>1 : 1 +>0 : 0 + +const f7: () => any = (x?) => 0; // Implicit any error +>f7 : () => any +>(x?) => 0 : (x?: any) => number +>x : any +>0 : 0 + +const f8: () => any = (...x) => 0; // [] +>f8 : () => any +>(...x) => 0 : () => number +>x : [] +>0 : 0 + +declare function g1(x: T): T; +>g1 : (x: T) => T +>x : T + +declare function g2(x: T): T; +>g2 : (x: T) => T +>x : T + +declare function g3(x: T): T; +>g3 : (x: T) => T +>x : T + +declare function g4(x: T): T; +>g4 : (x: T) => T +>x : T + +declare function g5 any>(x: T): T; +>g5 : any>(x: T) => T +>args : any[] +>x : T + +declare function g6 any>(x: T): T; +>g6 : any>(x: T) => T +>x : T + +g1((x = 1) => 0); // number +>g1((x = 1) => 0) : (x?: number) => 0 +>g1 : (x: T) => T +>(x = 1) => 0 : (x?: number) => 0 +>x : number +>1 : 1 +>0 : 0 + +g2((x = 1) => 0); // number +>g2((x = 1) => 0) : (x?: number) => 0 +>g2 : (x: T) => T +>(x = 1) => 0 : (x?: number) => 0 +>x : number +>1 : 1 +>0 : 0 + +g3((x = 1) => 0); // number +>g3((x = 1) => 0) : (x?: number) => 0 +>g3 : (x: T) => T +>(x = 1) => 0 : (x?: number) => 0 +>x : number +>1 : 1 +>0 : 0 + +g4((x = 1) => 0); // number +>g4((x = 1) => 0) : (x?: number) => 0 +>g4 : (x: T) => T +>(x = 1) => 0 : (x?: number) => 0 +>x : number +>1 : 1 +>0 : 0 + +g5((x = 1) => 0); // any +>g5((x = 1) => 0) : (x?: any) => number +>g5 : any>(x: T) => T +>(x = 1) => 0 : (x?: any) => number +>x : any +>1 : 1 +>0 : 0 + +g6((x = 1) => 0); // number +>g6((x = 1) => 0) : (x?: number) => number +>g6 : any>(x: T) => T +>(x = 1) => 0 : (x?: number) => number +>x : number +>1 : 1 +>0 : 0 + +g6((x?) => 0); // Implicit any error +>g6((x?) => 0) : (x?: any) => number +>g6 : any>(x: T) => T +>(x?) => 0 : (x?: any) => number +>x : any +>0 : 0 + +g6((...x) => 0); // [] +>g6((...x) => 0) : () => number +>g6 : any>(x: T) => T +>(...x) => 0 : () => number +>x : [] +>0 : 0 + // Repro from #28816 function id(input: T): T { return input } @@ -138,3 +280,98 @@ const newGetFoo2 = id(function getFoo ({ foo = 42 }) { }); +// Repro from comment in #30840 + +declare function memoize(func: F): F; +>memoize : (func: F) => F +>func : F + +function add(x: number, y = 0): number { +>add : (x: number, y?: number) => number +>x : number +>y : number +>0 : 0 + + return x + y; +>x + y : number +>x : number +>y : number +} +const memoizedAdd = memoize(add); +>memoizedAdd : (x: number, y?: number) => number +>memoize(add) : (x: number, y?: number) => number +>memoize : (func: F) => F +>add : (x: number, y?: number) => number + +const add2 = (x: number, y = 0): number => x + y; +>add2 : (x: number, y?: number) => number +>(x: number, y = 0): number => x + y : (x: number, y?: number) => number +>x : number +>y : number +>0 : 0 +>x + y : number +>x : number +>y : number + +const memoizedAdd2 = memoize(add2); +>memoizedAdd2 : (x: number, y?: number) => number +>memoize(add2) : (x: number, y?: number) => number +>memoize : (func: F) => F +>add2 : (x: number, y?: number) => number + +const memoizedAdd3 = memoize((x: number, y = 0): number => x + y); +>memoizedAdd3 : (x: number, y?: number) => number +>memoize((x: number, y = 0): number => x + y) : (x: number, y?: number) => number +>memoize : (func: F) => F +>(x: number, y = 0): number => x + y : (x: number, y?: number) => number +>x : number +>y : number +>0 : 0 +>x + y : number +>x : number +>y : number + +// Repro from #36052 + +declare function execute(script: string | Function): Promise; +>execute : (script: string | Function) => Promise +>script : string | Function + +export function executeSomething() { +>executeSomething : () => Promise + + return execute((root: HTMLElement, debug = true) => { +>execute((root: HTMLElement, debug = true) => { if (debug) { root.innerHTML = ''; } }) : Promise +>execute : (script: string | Function) => Promise +>(root: HTMLElement, debug = true) => { if (debug) { root.innerHTML = ''; } } : (root: HTMLElement, debug?: boolean) => void +>root : HTMLElement +>debug : boolean +>true : true + + if (debug) { +>debug : boolean + + root.innerHTML = ''; +>root.innerHTML = '' : "" +>root.innerHTML : string +>root : HTMLElement +>innerHTML : string +>'' : "" + } + }); +} + +const fz1 = (debug = true) => false; +>fz1 : (debug?: boolean) => boolean +>(debug = true) => false : (debug?: boolean) => boolean +>debug : boolean +>true : true +>false : false + +const fz2: Function = (debug = true) => false; +>fz2 : Function +>(debug = true) => false : (debug?: boolean) => boolean +>debug : boolean +>true : true +>false : false + diff --git a/tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts b/tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts index e68be5b7bfd8a..a095f14e3a4cc 100644 --- a/tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts +++ b/tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts @@ -8,16 +8,41 @@ declare function id4 any>(input: T): T; declare function id5 any>(input: T): T; const f10 = function ({ foo = 42 }) { return foo }; -const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error +const f11 = id1(function ({ foo = 42 }) { return foo }); const f12 = id2(function ({ foo = 42 }) { return foo }); const f13 = id3(function ({ foo = 42 }) { return foo }); const f14 = id4(function ({ foo = 42 }) { return foo }); const f20 = function (foo = 42) { return foo }; -const f21 = id1(function (foo = 42) { return foo }); // Implicit any error +const f21 = id1(function (foo = 42) { return foo }); const f22 = id2(function (foo = 42) { return foo }); const f25 = id5(function (foo = 42) { return foo }); +const f1 = (x = 1) => 0; // number +const f2: any = (x = 1) => 0; // number +const f3: unknown = (x = 1) => 0; // number +const f4: Function = (x = 1) => 0; // number +const f5: (...args: any[]) => any = (x = 1) => 0; // any +const f6: () => any = (x = 1) => 0; // number +const f7: () => any = (x?) => 0; // Implicit any error +const f8: () => any = (...x) => 0; // [] + +declare function g1(x: T): T; +declare function g2(x: T): T; +declare function g3(x: T): T; +declare function g4(x: T): T; +declare function g5 any>(x: T): T; +declare function g6 any>(x: T): T; + +g1((x = 1) => 0); // number +g2((x = 1) => 0); // number +g3((x = 1) => 0); // number +g4((x = 1) => 0); // number +g5((x = 1) => 0); // any +g6((x = 1) => 0); // number +g6((x?) => 0); // Implicit any error +g6((...x) => 0); // [] + // Repro from #28816 function id(input: T): T { return input } @@ -30,3 +55,32 @@ const newGetFoo = id(getFoo); const newGetFoo2 = id(function getFoo ({ foo = 42 }) { return foo; }); + +// Repro from comment in #30840 + +declare function memoize(func: F): F; + +function add(x: number, y = 0): number { + return x + y; +} +const memoizedAdd = memoize(add); + +const add2 = (x: number, y = 0): number => x + y; +const memoizedAdd2 = memoize(add2); + +const memoizedAdd3 = memoize((x: number, y = 0): number => x + y); + +// Repro from #36052 + +declare function execute(script: string | Function): Promise; + +export function executeSomething() { + return execute((root: HTMLElement, debug = true) => { + if (debug) { + root.innerHTML = ''; + } + }); +} + +const fz1 = (debug = true) => false; +const fz2: Function = (debug = true) => false; From 762ecf09ce6322ebdf99bb367469deae9b696be9 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 29 Jan 2020 09:09:55 -0800 Subject: [PATCH 5/6] Address CR feedback --- src/compiler/checker.ts | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 26c92707eb8fe..624ec75b658ed 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13688,31 +13688,32 @@ namespace ts { } function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { - if (isFunctionDeclaration(node) && (!isInJSFile(node) || !getTypeForDeclarationFromJSDocComment(node))) { - return false; - } + return (!isFunctionDeclaration(node) || isInJSFile(node) && !!getTypeForDeclarationFromJSDocComment(node)) && + (hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node)); + } + + function hasContextSensitiveParameters(node: FunctionLikeDeclaration) { // Functions with type parameters are not context sensitive. - if (node.typeParameters) { - return false; - } - // Functions with any parameters that lack type annotations are context sensitive. - if (some(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) { - return true; - } - if (node.kind !== SyntaxKind.ArrowFunction) { - // If the first parameter is not an explicit 'this' parameter, then the function has - // an implicit 'this' parameter which is subject to contextual typing. - const parameter = firstOrUndefined(node.parameters); - if (!(parameter && parameterIsThisKeyword(parameter))) { + if (!node.typeParameters) { + // Functions with any parameters that lack type annotations are context sensitive. + if (some(node.parameters, p => !getEffectiveTypeAnnotationNode(p))) { return true; } + if (node.kind !== SyntaxKind.ArrowFunction) { + // If the first parameter is not an explicit 'this' parameter, then the function has + // an implicit 'this' parameter which is subject to contextual typing. + const parameter = firstOrUndefined(node.parameters); + if (!(parameter && parameterIsThisKeyword(parameter))) { + return true; + } + } } - return hasContextSensitiveReturnExpression(node); + return false; } function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) { // TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value. - return !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body); + return !getEffectiveReturnTypeNode(node) && !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body); } function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { @@ -26427,7 +26428,7 @@ namespace ts { // The identityMapper object is used to indicate that function expressions are wildcards if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) { // Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage - if (!getEffectiveReturnTypeNode(node) && node.kind === SyntaxKind.ArrowFunction && node.parameters.length === 0) { + if (!getEffectiveReturnTypeNode(node) && !hasContextSensitiveParameters(node)) { // Return plain anyFunctionType if there is no possibility we'll make inferences from the return type const contextualSignature = getContextualSignature(node); if (contextualSignature && couldContainTypeVariables(getReturnTypeOfSignature(contextualSignature))) { From 5e88ac7700f4c90d66dab994b947ae660fa30b26 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Wed, 29 Jan 2020 14:22:08 -0800 Subject: [PATCH 6/6] Add fourslash tests --- ...quickInfoForContextuallyTypedParameters.ts | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/cases/fourslash/quickInfoForContextuallyTypedParameters.ts diff --git a/tests/cases/fourslash/quickInfoForContextuallyTypedParameters.ts b/tests/cases/fourslash/quickInfoForContextuallyTypedParameters.ts new file mode 100644 index 0000000000000..d394e147d7014 --- /dev/null +++ b/tests/cases/fourslash/quickInfoForContextuallyTypedParameters.ts @@ -0,0 +1,40 @@ +/// + +////declare function foo1(obj: T, settings: (row: T) => { value: string, func?: Function }): void; +//// +////foo1(new Error(), +//// o/*1*/ => ({ +//// value: o.name, +//// func: x => 'foo' +//// }) +////); +//// +////declare function foo2(settings: (row: T) => { value: string, func?: Function }, obj: T): void; +//// +////foo2(o/*2*/ => ({ +//// value: o.name, +//// func: x => 'foo' +//// }), +//// new Error(), +////); +//// +////declare function foof(settings: (row: T) => { value: T[U], func?: Function }, obj: T, key: U): U; +//// +////function q(x: T): T["name"] { +//// return foof/*3*/(o => ({ value: o.name, func: x => 'foo' }), x, "name"); +////} +//// +////foof/*4*/(o => ({ value: o.name, func: x => 'foo' }), new Error(), "name"); + +verify.quickInfos({ + 1: "(parameter) o: Error", + 2: "(parameter) o: Error", + 3: `function foof(settings: (row: T) => { + value: T["name"]; + func?: Function; +}, obj: T, key: "name"): "name"`, + 4: `function foof(settings: (row: Error) => { + value: string; + func?: Function; +}, obj: Error, key: "name"): "name"` +});