From 1cb9110d4c548294c8e189210da591f022bdbb12 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 6 Apr 2020 15:43:04 -0700 Subject: [PATCH] Look for outer type parameters on VariableStatements This only applies in JS, where `@template` tags can apply to initialisers of variable declarations: ```js /** * @template T * @returns {(b: T) => T} */ const seq = a => b => b ``` Fixes #36201 --- src/compiler/checker.ts | 4 +++ ...lateTagTypeParameterOnVariableStatement.js | 23 ++++++++++++++ ...agTypeParameterOnVariableStatement.symbols | 25 +++++++++++++++ ...eTagTypeParameterOnVariableStatement.types | 31 +++++++++++++++++++ ...lateTagTypeParameterOnVariableStatement.ts | 17 ++++++++++ 5 files changed, 100 insertions(+) create mode 100644 tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.js create mode 100644 tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.symbols create mode 100644 tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.types create mode 100644 tests/cases/conformance/jsdoc/instantiateTemplateTagTypeParameterOnVariableStatement.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index db5002d0b1bd4..efdd3902432cf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8238,6 +8238,7 @@ namespace ts { return undefined; } switch (node.kind) { + case SyntaxKind.VariableStatement: case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: case SyntaxKind.InterfaceDeclaration: @@ -8265,6 +8266,9 @@ namespace ts { else if (node.kind === SyntaxKind.ConditionalType) { return concatenate(outerTypeParameters, getInferTypeParameters(node)); } + else if (node.kind === SyntaxKind.VariableStatement && !isInJSFile(node)) { + break; + } const outerAndOwnTypeParameters = appendTypeParameters(outerTypeParameters, getEffectiveTypeParameterDeclarations(node)); const thisType = includeThisTypes && (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.InterfaceDeclaration || isJSConstructor(node)) && diff --git a/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.js b/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.js new file mode 100644 index 0000000000000..0db9d9355c772 --- /dev/null +++ b/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.js @@ -0,0 +1,23 @@ +//// [instantiateTemplateTagTypeParameterOnVariableStatement.js] +/** + * @template T + * @param {T} a + * @returns {(b: T) => T} + */ +const seq = a => b => b; + +const text1 = "hello"; +const text2 = "world"; + +/** @type {string} */ +var text3 = seq(text1)(text2); + + + + +//// [instantiateTemplateTagTypeParameterOnVariableStatement.d.ts] +declare function seq(a: T): (b: T) => T; +declare const text1: "hello"; +declare const text2: "world"; +/** @type {string} */ +declare var text3: string; diff --git a/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.symbols b/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.symbols new file mode 100644 index 0000000000000..74b7bd1f028d5 --- /dev/null +++ b/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.symbols @@ -0,0 +1,25 @@ +=== tests/cases/conformance/jsdoc/instantiateTemplateTagTypeParameterOnVariableStatement.js === +/** + * @template T + * @param {T} a + * @returns {(b: T) => T} + */ +const seq = a => b => b; +>seq : Symbol(seq, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 5, 5)) +>a : Symbol(a, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 5, 11)) +>b : Symbol(b, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 5, 16)) +>b : Symbol(b, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 5, 16)) + +const text1 = "hello"; +>text1 : Symbol(text1, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 7, 5)) + +const text2 = "world"; +>text2 : Symbol(text2, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 8, 5)) + +/** @type {string} */ +var text3 = seq(text1)(text2); +>text3 : Symbol(text3, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 11, 3)) +>seq : Symbol(seq, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 5, 5)) +>text1 : Symbol(text1, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 7, 5)) +>text2 : Symbol(text2, Decl(instantiateTemplateTagTypeParameterOnVariableStatement.js, 8, 5)) + diff --git a/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.types b/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.types new file mode 100644 index 0000000000000..a817bcec75b6c --- /dev/null +++ b/tests/baselines/reference/instantiateTemplateTagTypeParameterOnVariableStatement.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/jsdoc/instantiateTemplateTagTypeParameterOnVariableStatement.js === +/** + * @template T + * @param {T} a + * @returns {(b: T) => T} + */ +const seq = a => b => b; +>seq : (a: T) => (b: T) => T +>a => b => b : (a: T) => (b: T) => T +>a : T +>b => b : (b: T) => T +>b : T +>b : T + +const text1 = "hello"; +>text1 : "hello" +>"hello" : "hello" + +const text2 = "world"; +>text2 : "world" +>"world" : "world" + +/** @type {string} */ +var text3 = seq(text1)(text2); +>text3 : string +>seq(text1)(text2) : string +>seq(text1) : (b: string) => string +>seq : (a: T) => (b: T) => T +>text1 : "hello" +>text2 : "world" + diff --git a/tests/cases/conformance/jsdoc/instantiateTemplateTagTypeParameterOnVariableStatement.ts b/tests/cases/conformance/jsdoc/instantiateTemplateTagTypeParameterOnVariableStatement.ts new file mode 100644 index 0000000000000..b20d191d3dae6 --- /dev/null +++ b/tests/cases/conformance/jsdoc/instantiateTemplateTagTypeParameterOnVariableStatement.ts @@ -0,0 +1,17 @@ +// @checkJs: true +// @allowJs: true +// @declaration: true +// @emitDeclarationOnly: true +// @filename: instantiateTemplateTagTypeParameterOnVariableStatement.js +/** + * @template T + * @param {T} a + * @returns {(b: T) => T} + */ +const seq = a => b => b; + +const text1 = "hello"; +const text2 = "world"; + +/** @type {string} */ +var text3 = seq(text1)(text2);