diff --git a/src/services/services.ts b/src/services/services.ts index 7c98e650a16c9..4e0a0265b9193 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1901,7 +1901,7 @@ namespace ts { sourceMapText = text; } else { - Debug.assert(outputText === undefined, "Unexpected multiple outputs for the file: " + name); + Debug.assert(outputText === undefined, `Unexpected multiple outputs for the file: '${name}'`); outputText = text; } }, @@ -4248,28 +4248,31 @@ namespace ts { } else { // Method/function type parameter - let container = getContainingFunction(location); - if (container) { - let signatureDeclaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent; - let signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration); - if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) { - displayParts.push(keywordPart(SyntaxKind.NewKeyword)); - displayParts.push(spacePart()); + let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter); + Debug.assert(declaration !== undefined); + declaration = declaration.parent; + + if (declaration) { + if (isFunctionLikeKind(declaration.kind)) { + const signature = typeChecker.getSignatureFromDeclaration(declaration); + if (declaration.kind === SyntaxKind.ConstructSignature) { + displayParts.push(keywordPart(SyntaxKind.NewKeyword)); + displayParts.push(spacePart()); + } + else if (declaration.kind !== SyntaxKind.CallSignature && (declaration).name) { + addFullSymbolName(declaration.symbol); + } + addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); } - else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) { - addFullSymbolName(signatureDeclaration.symbol); + else { + // Type alias type parameter + // For example + // type list = T[]; // Both T will go through same code path + displayParts.push(keywordPart(SyntaxKind.TypeKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(declaration.symbol); + writeTypeParametersOfSymbol(declaration.symbol, sourceFile); } - addRange(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); - } - else { - // Type aliash type parameter - // For example - // type list = T[]; // Both T will go through same code path - let declaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent; - displayParts.push(keywordPart(SyntaxKind.TypeKeyword)); - displayParts.push(spacePart()); - addFullSymbolName(declaration.symbol); - writeTypeParametersOfSymbol(declaration.symbol, sourceFile); } } } diff --git a/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias3.ts b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias3.ts new file mode 100644 index 0000000000000..59cceda2aad48 --- /dev/null +++ b/tests/cases/fourslash/completionListInTypeParameterOfTypeAlias3.ts @@ -0,0 +1,13 @@ +/// + +//// type constructorType = new + +//// type MixinCtor = new () => /*0*/A & { constructor: MixinCtor }; +//// type MixinCtor = new () => A & { constructor: { constructor: MixinCtor } }; + +let typeAliashDisplayParts = [{ text: "type", kind: "keyword" }, { text: " ", kind: "space" }, { text: "MixinCtor", kind: "aliasName" }, + { text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }]; + +let typeParameterDisplayParts = [{ text: "(", kind: "punctuation" }, { text: "type parameter", kind: "text" }, { text: ")", kind: "punctuation" }, { text: " ", kind: "space" }, + { text: "A", kind: "typeParameterName" }, { text: " ", kind: "space" }, { text: "in", kind: "keyword" }, { text: " ", kind: "space" }]; + +goTo.marker('0'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("0").position, length: "A".length }, + typeParameterDisplayParts.concat(typeAliashDisplayParts), []); + +goTo.marker('1'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("1").position, length: "A".length }, + typeParameterDisplayParts.concat(typeAliashDisplayParts), []);; + +goTo.marker('2'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("2").position, length: "A".length }, + typeParameterDisplayParts.concat(typeAliashDisplayParts), []); \ No newline at end of file diff --git a/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterInTypeAlias.ts b/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterInTypeAlias.ts index b6a10e086c25b..5dbcfa93d783e 100644 --- a/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterInTypeAlias.ts +++ b/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterInTypeAlias.ts @@ -3,9 +3,6 @@ ////type /*0*/List = /*2*/T[] ////type /*3*/List2 = /*5*/T[]; -type List2 = T[]; - -type L = T[] let typeAliashDisplayParts = [{ text: "type", kind: "keyword" }, { text: " ", kind: "space" }, { text: "List", kind: "aliasName" }, { text: "<", kind: "punctuation" }, { text: "T", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }]; diff --git a/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterOfFunctionLikeInTypeAlias.ts b/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterOfFunctionLikeInTypeAlias.ts new file mode 100644 index 0000000000000..917358fde570b --- /dev/null +++ b/tests/cases/fourslash/quickInfoDisplayPartsTypeParameterOfFunctionLikeInTypeAlias.ts @@ -0,0 +1,41 @@ +/// + +//// type jamming = new () => jamming; +//// type jamming = (new () => jamming) & { constructor: /*2*/A }; +//// type jamming = new () => jamming & { constructor: /*3*/A }; + +let typeAliashDisplayParts = [{ text: "type", kind: "keyword" }, { text: " ", kind: "space" }, { text: "jamming", kind: "aliasName" }, + { text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }]; + +let typeParameterDisplayParts = [{ text: "(", kind: "punctuation" }, { text: "type parameter", kind: "text" }, { text: ")", kind: "punctuation" }, { text: " ", kind: "space" }, + { text: "A", kind: "typeParameterName" }, { text: " ", kind: "space" }, { text: "in", kind: "keyword" }, { text: " ", kind: "space" }]; + +let constructorTypeDisplayParts = [{ text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, { text: ">", kind: "punctuation" }, + { text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" }, { text: ":", kind: "punctuation" }, { text: " ", kind: "space" }, + { text: "new", kind: "keyword" }, { "text": " ", kind: "space" }, { text: "<", kind: "punctuation" }, { text: "A", kind: "typeParameterName" }, + { text: ">", kind: "punctuation" }, { text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" }, {"text": " ", kind: "space" }, + { text: "=>", kind: "punctuation" }, { "text": " ", kind: "space" }, { text: "jamming", kind: "aliasName" }]; + +let constructorTypeWithLongReturnTypeDisplayParts = [{ "text": "<", kind: "punctuation" }, { "text": "A", kind: "typeParameterName" }, { "text": ">", kind: "punctuation" }, + { "text": "(", kind: "punctuation" }, { "text": ")", kind: "punctuation" }, { "text": ":", kind: "punctuation" }, { "text": " ", kind: "space" }, { "text": "(", kind: "punctuation" }, + { "text": "new", kind: "keyword" }, { "text": " ", kind: "space" }, { "text": "<", kind: "punctuation" }, { "text": "A", kind: "typeParameterName" }, { "text": ">", kind: "punctuation" }, + { "text": "(", kind: "punctuation" }, { "text": ")", kind: "punctuation" }, { "text": " ", kind: "space" }, { "text": "=>", kind: "punctuation" }, { "text": " ", kind: "space" }, + { "text": "jamming", kind: "aliasName" }, { "text": ")", kind: "punctuation" }, { "text": " ", kind: "space" }, { "text": "&", kind: "punctuation" }, { "text": " ", kind: "space" }, + { "text": "{", kind: "punctuation" }, { "text": "\n", kind: "lineBreak" }, { "text": " ", kind: "space" }, { "text": "constructor", kind: "propertyName" }, { "text": ":", kind: "punctuation" }, + { "text": " ", kind: "space" }, { "text": "A", kind: "typeParameterName" }, {"text":";", kind: "punctuation" }, {"text":"\n", kind: "lineBreak" }, {"text":"}", kind: "punctuation" }]; + +goTo.marker('0'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("0").position, length: "A".length }, + typeParameterDisplayParts.concat(constructorTypeDisplayParts), []); + +goTo.marker('1'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("1").position, length: "A".length }, + typeParameterDisplayParts.concat(constructorTypeDisplayParts), []); + +goTo.marker('2'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("2").position, length: "A".length }, + typeParameterDisplayParts.concat(typeAliashDisplayParts), []); + +goTo.marker('3'); +verify.verifyQuickInfoDisplayParts("type parameter", "", { start: test.markerByName("3").position, length: "A".length }, + typeParameterDisplayParts.concat(constructorTypeWithLongReturnTypeDisplayParts), []); \ No newline at end of file