From 7d1c95a32bdd9ae6a787430d215c276ba75f51cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Sat, 9 Mar 2024 11:36:10 +0100 Subject: [PATCH] Consider annotated parameter with an initializer as optional when inferring from it --- src/compiler/checker.ts | 2 +- ...mAnnotatedParameterWithInitializer.symbols | 73 ++++++++++++++++++ ...romAnnotatedParameterWithInitializer.types | 75 +++++++++++++++++++ ...erFromAnnotatedParameterWithInitializer.ts | 21 ++++++ 4 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.symbols create mode 100644 tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.types create mode 100644 tests/cases/compiler/inferFromAnnotatedParameterWithInitializer.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f175b6806551b..c3d1ce8fd2138 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -36542,7 +36542,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const declaration = signature.parameters[i].valueDeclaration as ParameterDeclaration; const typeNode = getEffectiveTypeAnnotationNode(declaration); if (typeNode) { - const source = addOptionality(getTypeFromTypeNode(typeNode), /*isProperty*/ false, isOptionalDeclaration(declaration)); + const source = addOptionality(getTypeFromTypeNode(typeNode), /*isProperty*/ false, hasInitializer(declaration) || isOptionalDeclaration(declaration)); const target = getTypeAtPosition(context, i); inferTypes(inferenceContext.inferences, source, target); } diff --git a/tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.symbols b/tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.symbols new file mode 100644 index 0000000000000..35b6f88fcf3a1 --- /dev/null +++ b/tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.symbols @@ -0,0 +1,73 @@ +//// [tests/cases/compiler/inferFromAnnotatedParameterWithInitializer.ts] //// + +=== inferFromAnnotatedParameterWithInitializer.ts === +// https://github.com/microsoft/TypeScript/issues/57706 + +declare function infer1(fn: Factory): T; +>infer1 : Symbol(infer1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 0, 0)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 24)) +>fn : Symbol(fn, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 27)) +>Factory : Symbol(Factory, Decl(inferFromAnnotatedParameterWithInitializer.ts, 3, 47)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 24)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 24)) + +declare function infer2(fn: Factory2): T; +>infer2 : Symbol(infer2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 46)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 3, 24)) +>fn : Symbol(fn, Decl(inferFromAnnotatedParameterWithInitializer.ts, 3, 27)) +>Factory2 : Symbol(Factory2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 5, 53)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 3, 24)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 3, 24)) + +export type Factory = (arg1: T, arg2: any) => any; +>Factory : Symbol(Factory, Decl(inferFromAnnotatedParameterWithInitializer.ts, 3, 47)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 5, 20)) +>arg1 : Symbol(arg1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 5, 26)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 5, 20)) +>arg2 : Symbol(arg2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 5, 34)) + +export type Factory2 = (...args: [T, any]) => any; +>Factory2 : Symbol(Factory2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 5, 53)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 6, 21)) +>args : Symbol(args, Decl(inferFromAnnotatedParameterWithInitializer.ts, 6, 27)) +>T : Symbol(T, Decl(inferFromAnnotatedParameterWithInitializer.ts, 6, 21)) + +const f1 = (msg: string = "hello", test: any) => {}; +>f1 : Symbol(f1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 8, 5)) +>msg : Symbol(msg, Decl(inferFromAnnotatedParameterWithInitializer.ts, 8, 12)) +>test : Symbol(test, Decl(inferFromAnnotatedParameterWithInitializer.ts, 8, 34)) + +const a1 = infer1(f1); +>a1 : Symbol(a1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 9, 5)) +>infer1 : Symbol(infer1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 0, 0)) +>f1 : Symbol(f1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 8, 5)) + +const a2 = infer2(f1); +>a2 : Symbol(a2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 10, 5)) +>infer2 : Symbol(infer2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 46)) +>f1 : Symbol(f1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 8, 5)) + +const f2 = (msg: string = "hello") => {}; +>f2 : Symbol(f2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 12, 5)) +>msg : Symbol(msg, Decl(inferFromAnnotatedParameterWithInitializer.ts, 12, 12)) + +const b1 = infer1(f2); +>b1 : Symbol(b1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 13, 5)) +>infer1 : Symbol(infer1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 0, 0)) +>f2 : Symbol(f2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 12, 5)) + +const b2 = infer2(f2); +>b2 : Symbol(b2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 14, 5)) +>infer2 : Symbol(infer2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 46)) +>f2 : Symbol(f2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 12, 5)) + +const c1 = infer1((msg: string = "hello") => {}); +>c1 : Symbol(c1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 16, 5)) +>infer1 : Symbol(infer1, Decl(inferFromAnnotatedParameterWithInitializer.ts, 0, 0)) +>msg : Symbol(msg, Decl(inferFromAnnotatedParameterWithInitializer.ts, 16, 19)) + +const c2 = infer2((msg: string = "hello") => {}); +>c2 : Symbol(c2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 17, 5)) +>infer2 : Symbol(infer2, Decl(inferFromAnnotatedParameterWithInitializer.ts, 2, 46)) +>msg : Symbol(msg, Decl(inferFromAnnotatedParameterWithInitializer.ts, 17, 19)) + diff --git a/tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.types b/tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.types new file mode 100644 index 0000000000000..fb221f3ec5136 --- /dev/null +++ b/tests/baselines/reference/inferFromAnnotatedParameterWithInitializer.types @@ -0,0 +1,75 @@ +//// [tests/cases/compiler/inferFromAnnotatedParameterWithInitializer.ts] //// + +=== inferFromAnnotatedParameterWithInitializer.ts === +// https://github.com/microsoft/TypeScript/issues/57706 + +declare function infer1(fn: Factory): T; +>infer1 : (fn: Factory) => T +>fn : Factory + +declare function infer2(fn: Factory2): T; +>infer2 : (fn: Factory2) => T +>fn : Factory2 + +export type Factory = (arg1: T, arg2: any) => any; +>Factory : Factory +>arg1 : T +>arg2 : any + +export type Factory2 = (...args: [T, any]) => any; +>Factory2 : Factory2 +>args : [T, any] + +const f1 = (msg: string = "hello", test: any) => {}; +>f1 : (msg: string | undefined, test: any) => void +>(msg: string = "hello", test: any) => {} : (msg: string | undefined, test: any) => void +>msg : string +>"hello" : "hello" +>test : any + +const a1 = infer1(f1); +>a1 : string | undefined +>infer1(f1) : string | undefined +>infer1 : (fn: Factory) => T +>f1 : (msg: string | undefined, test: any) => void + +const a2 = infer2(f1); +>a2 : string | undefined +>infer2(f1) : string | undefined +>infer2 : (fn: Factory2) => T +>f1 : (msg: string | undefined, test: any) => void + +const f2 = (msg: string = "hello") => {}; +>f2 : (msg?: string) => void +>(msg: string = "hello") => {} : (msg?: string) => void +>msg : string +>"hello" : "hello" + +const b1 = infer1(f2); +>b1 : string | undefined +>infer1(f2) : string | undefined +>infer1 : (fn: Factory) => T +>f2 : (msg?: string) => void + +const b2 = infer2(f2); +>b2 : string | undefined +>infer2(f2) : string | undefined +>infer2 : (fn: Factory2) => T +>f2 : (msg?: string) => void + +const c1 = infer1((msg: string = "hello") => {}); +>c1 : string | undefined +>infer1((msg: string = "hello") => {}) : string | undefined +>infer1 : (fn: Factory) => T +>(msg: string = "hello") => {} : (msg?: string) => void +>msg : string +>"hello" : "hello" + +const c2 = infer2((msg: string = "hello") => {}); +>c2 : string | undefined +>infer2((msg: string = "hello") => {}) : string | undefined +>infer2 : (fn: Factory2) => T +>(msg: string = "hello") => {} : (msg?: string) => void +>msg : string +>"hello" : "hello" + diff --git a/tests/cases/compiler/inferFromAnnotatedParameterWithInitializer.ts b/tests/cases/compiler/inferFromAnnotatedParameterWithInitializer.ts new file mode 100644 index 0000000000000..b7628aa30a525 --- /dev/null +++ b/tests/cases/compiler/inferFromAnnotatedParameterWithInitializer.ts @@ -0,0 +1,21 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/57706 + +declare function infer1(fn: Factory): T; +declare function infer2(fn: Factory2): T; + +export type Factory = (arg1: T, arg2: any) => any; +export type Factory2 = (...args: [T, any]) => any; + +const f1 = (msg: string = "hello", test: any) => {}; +const a1 = infer1(f1); +const a2 = infer2(f1); + +const f2 = (msg: string = "hello") => {}; +const b1 = infer1(f2); +const b2 = infer2(f2); + +const c1 = infer1((msg: string = "hello") => {}); +const c2 = infer2((msg: string = "hello") => {});