From 724dc6ce19c19ca8a7dc11b36c77674f6e524943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Mon, 21 Aug 2023 23:16:47 +0200 Subject: [PATCH] Instantiable tuple labels --- src/compiler/checker.ts | 41 +++++++---- src/compiler/factory/nodeFactory.ts | 5 +- src/compiler/parser.ts | 23 +++++-- src/compiler/types.ts | 8 ++- src/compiler/utilities.ts | 6 ++ src/compiler/visitorPublic.ts | 3 +- tests/baselines/reference/api/typescript.d.ts | 7 +- .../instantiableTupleLabels1.errors.txt | 40 +++++++++++ .../reference/instantiableTupleLabels1.js | 49 +++++++++++++ .../instantiableTupleLabels1.symbols | 68 +++++++++++++++++++ .../reference/instantiableTupleLabels1.types | 54 +++++++++++++++ .../types/tuple/instantiableTupleLabels1.ts | 25 +++++++ 12 files changed, 302 insertions(+), 27 deletions(-) create mode 100644 tests/baselines/reference/instantiableTupleLabels1.errors.txt create mode 100644 tests/baselines/reference/instantiableTupleLabels1.js create mode 100644 tests/baselines/reference/instantiableTupleLabels1.symbols create mode 100644 tests/baselines/reference/instantiableTupleLabels1.types create mode 100644 tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9c6b8237a7f74..f1f6db9cb9609 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7004,11 +7004,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (let i = 0; i < tupleConstituentNodes.length; i++) { const flags = (type.target as TupleType).elementFlags[i]; const labeledElementDeclaration = labeledElementDeclarations?.[i]; + const label = labeledElementDeclaration && getTupleElementLabel(type as TupleTypeReference, labeledElementDeclaration); - if (labeledElementDeclaration) { + if (label) { tupleConstituentNodes[i] = factory.createNamedTupleMember( flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, - factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel(labeledElementDeclaration))), + factory.createIdentifier(unescapeLeadingUnderscores(label)), flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i], @@ -12954,7 +12955,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getUniqAssociatedNamesFromTupleType(type: TupleTypeReference, restName: __String) { const associatedNamesMap = new Map<__String, number>(); return map(type.target.labeledElementDeclarations, (labeledElement, i) => { - const name = getTupleElementLabel(labeledElement, i, restName); + const name = getTupleElementLabel(type, labeledElement, i, restName); const prevCounter = associatedNamesMap.get(name); if (prevCounter === undefined) { associatedNamesMap.set(name, 1); @@ -35297,13 +35298,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember): __String; - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember | undefined, index: number, restParameterName?: __String): __String; - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember | undefined, index?: number, restParameterName = "arg" as __String) { + function getTupleElementLabel(tupleType: TupleTypeReference, d: ParameterDeclaration | NamedTupleMember): __String | undefined; + function getTupleElementLabel(tupleType: TupleTypeReference, d: ParameterDeclaration | NamedTupleMember | undefined, index: number, restParameterName?: __String): __String; + function getTupleElementLabel(tupleType: TupleTypeReference, d: ParameterDeclaration | NamedTupleMember | undefined, index?: number, restParameterName = "arg" as __String) { if (!d) { return `${restParameterName}_${index}` as __String; } - Debug.assert(isIdentifier(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names + Debug.assert(!isBindingPattern(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names with them + if (d.name.kind === SyntaxKind.TemplateLiteralType) { + const label = instantiateType(getTypeFromTypeNode(d.name), tupleType.mapper); + return label.flags & TypeFlags.StringLiteral + ? escapeLeadingUnderscores((label as StringLiteralType).value) + : typeof index === "number" + ? `${restParameterName}_${index}` as __String + : undefined; + } + if (d.name.kind === SyntaxKind.NoSubstitutionTemplateLiteral) { + return escapeLeadingUnderscores(d.name.text); + } return d.name.escapedText; } @@ -35315,9 +35327,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const restParameter = signature.parameters[paramCount] || unknownSymbol; const restType = overrideRestType || getTypeOfSymbol(restParameter); if (isTupleType(restType)) { - const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; + const associatedNames = restType.target.labeledElementDeclarations; const index = pos - paramCount; - return getTupleElementLabel(associatedNames?.[index], index, restParameter.escapedName); + return getTupleElementLabel(restType, associatedNames?.[index], index, restParameter.escapedName); } return restParameter.escapedName; } @@ -35345,13 +35357,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const restType = getTypeOfSymbol(restParameter); if (isTupleType(restType)) { - const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; + const associatedNames = restType.target.labeledElementDeclarations; const index = pos - paramCount; const associatedName = associatedNames?.[index]; const isRestTupleElement = !!associatedName?.dotDotDotToken; - if (associatedName) { - Debug.assert(isIdentifier(associatedName.name)); + // TODO: figure out the non-identifier case here + if (associatedName && isIdentifier(associatedName.name)) { return { parameter: associatedName.name, parameterName: associatedName.name.escapedText, isRestParameter: isRestTupleElement }; } @@ -35380,7 +35392,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const restParameter = signature.parameters[paramCount] || unknownSymbol; const restType = getTypeOfSymbol(restParameter); if (isTupleType(restType)) { - const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; + const associatedNames = restType.target.labeledElementDeclarations; const index = pos - paramCount; return associatedNames && associatedNames[index]; } @@ -39580,6 +39592,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.type.kind === SyntaxKind.RestType) { grammarErrorOnNode(node.type, Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type); } + if (node.name.kind === SyntaxKind.TemplateLiteralType) { + checkSourceElement(node.name); + } checkSourceElement(node.type); getTypeFromTypeNode(node); } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index ededdbd057ab9..1971ccd90fc50 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -326,6 +326,7 @@ import { NamedImportBindings, NamedImports, NamedTupleMember, + NamedTupleMemberName, NamespaceExport, NamespaceExportDeclaration, NamespaceImport, @@ -2499,7 +2500,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { + function createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: NamedTupleMemberName, questionToken: QuestionToken | undefined, type: TypeNode) { const node = createBaseDeclaration(SyntaxKind.NamedTupleMember); node.dotDotDotToken = dotDotDotToken; node.name = name; @@ -2512,7 +2513,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode } // @api - function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode) { + function updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: NamedTupleMemberName, questionToken: QuestionToken | undefined, type: TypeNode) { return node.dotDotDotToken !== dotDotDotToken || node.name !== name || node.questionToken !== questionToken diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 08a70b437a973..704d04a34a7cd 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4404,23 +4404,36 @@ namespace Parser { return type; } - function isNextTokenColonOrQuestionColon() { - return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); + function isTokenColonOrQuestionColon() { + return token() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken); } function isTupleElementName() { if (token() === SyntaxKind.DotDotDotToken) { - return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon(); + nextToken(); + } + if (token() === SyntaxKind.TemplateHead) { + parseTemplateType(); + return isTokenColonOrQuestionColon(); + } + if (tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.NoSubstitutionTemplateLiteral) { + nextToken(); + return isTokenColonOrQuestionColon(); } - return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon(); + return false; } function parseTupleElementNameOrTupleElementType() { + // TODO: optimize this so we don't have to do lookahead if (lookAhead(isTupleElementName)) { const pos = getNodePos(); const hasJSDoc = hasPrecedingJSDocComment(); const dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken); - const name = parseIdentifierName(); + const name = token() === SyntaxKind.NoSubstitutionTemplateLiteral + ? (parseLiteralLikeNode(token()) as NoSubstitutionTemplateLiteral) + : token() === SyntaxKind.TemplateHead + ? parseTemplateType() + : parseIdentifierName(); const questionToken = parseOptionalToken(SyntaxKind.QuestionToken); parseExpected(SyntaxKind.ColonToken); const type = parseTupleElementType(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 14575e7f1733d..0abbb6ce4052f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2222,10 +2222,12 @@ export interface TupleTypeNode extends TypeNode { readonly elements: NodeArray; } +export type NamedTupleMemberName = Identifier | NoSubstitutionTemplateLiteral | TemplateLiteralTypeNode; + export interface NamedTupleMember extends TypeNode, Declaration, JSDocContainer { readonly kind: SyntaxKind.NamedTupleMember; readonly dotDotDotToken?: Token; - readonly name: Identifier; + readonly name: NamedTupleMemberName; readonly questionToken?: Token; readonly type: TypeNode; } @@ -8379,8 +8381,8 @@ export interface NodeFactory { updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode; createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; - createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; - updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; + createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: NamedTupleMemberName, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; + updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: NamedTupleMemberName, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; createOptionalTypeNode(type: TypeNode): OptionalTypeNode; updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode; createRestTypeNode(type: TypeNode): RestTypeNode; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2edd5b0243bc8..07f2ba047dcf5 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -403,6 +403,7 @@ import { NamedExports, NamedImports, NamedImportsOrExports, + NamedTupleMemberName, NamespaceExport, NamespaceImport, NewExpression, @@ -10434,3 +10435,8 @@ export function getPropertyNameFromType(type: StringLiteralType | NumberLiteralT } return Debug.fail(); } + +/** @internal */ +export function isNamedTupleMemberName(node: Node): node is NamedTupleMemberName { + return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.TemplateLiteralType || node.kind === SyntaxKind.NoSubstitutionTemplateLiteral; +} diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 109614c3244b2..dfff1636a6fef 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -63,6 +63,7 @@ import { isModuleReference, isNamedExportBindings, isNamedImportBindings, + isNamedTupleMemberName, isObjectLiteralElementLike, isOptionalChain, isParameter, @@ -913,7 +914,7 @@ const visitEachChildTable: VisitEachChildTable = { return context.factory.updateNamedTupleMember( node, tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, - Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + Debug.checkDefined(nodeVisitor(node.name, visitor, isNamedTupleMemberName)), tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), ); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index dcea4be64289a..7af3b866be342 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -5196,10 +5196,11 @@ declare namespace ts { readonly kind: SyntaxKind.TupleType; readonly elements: NodeArray; } + type NamedTupleMemberName = Identifier | NoSubstitutionTemplateLiteral | TemplateLiteralTypeNode; interface NamedTupleMember extends TypeNode, Declaration, JSDocContainer { readonly kind: SyntaxKind.NamedTupleMember; readonly dotDotDotToken?: Token; - readonly name: Identifier; + readonly name: NamedTupleMemberName; readonly questionToken?: Token; readonly type: TypeNode; } @@ -7932,8 +7933,8 @@ declare namespace ts { updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode; createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]): TupleTypeNode; - createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; - updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: Identifier, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; + createNamedTupleMember(dotDotDotToken: DotDotDotToken | undefined, name: NamedTupleMemberName, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; + updateNamedTupleMember(node: NamedTupleMember, dotDotDotToken: DotDotDotToken | undefined, name: NamedTupleMemberName, questionToken: QuestionToken | undefined, type: TypeNode): NamedTupleMember; createOptionalTypeNode(type: TypeNode): OptionalTypeNode; updateOptionalTypeNode(node: OptionalTypeNode, type: TypeNode): OptionalTypeNode; createRestTypeNode(type: TypeNode): RestTypeNode; diff --git a/tests/baselines/reference/instantiableTupleLabels1.errors.txt b/tests/baselines/reference/instantiableTupleLabels1.errors.txt new file mode 100644 index 0000000000000..9550e02a23b04 --- /dev/null +++ b/tests/baselines/reference/instantiableTupleLabels1.errors.txt @@ -0,0 +1,40 @@ +instantiableTupleLabels1.ts(4,27): error TS5087: A labeled tuple element is declared as rest with a '...' before the name, rather than before the type. +instantiableTupleLabels1.ts(15,24): error TS2322: Type 'unknown' is not assignable to type 'string | number | bigint | boolean | null | undefined'. +instantiableTupleLabels1.ts(18,46): error TS2322: Type 'T1' is not assignable to type 'string | number | bigint | boolean | null | undefined'. +instantiableTupleLabels1.ts(18,71): error TS2322: Type 'T2' is not assignable to type 'string | number | bigint | boolean | null | undefined'. + + +==== instantiableTupleLabels1.ts (4 errors) ==== + type T1 = [`wow`: boolean]; + type T2 = [number, `wow`: boolean]; + type T3 = [number, ...`wow`: boolean[]]; + type T4 = [number, `wow`: ...boolean[]]; // error + ~~~~~~~~~~~~ +!!! error TS5087: A labeled tuple element is declared as rest with a '...' before the name, rather than before the type. + + type Prefix = 'pre'; + + type T5 = [`${Prefix}wow`: boolean]; + type T6 = [number, `${Prefix}wow`: boolean]; + type T7 = [number, ...`${Prefix}wow`: boolean[]]; + + type T8 = [number, `${never}wontfly`: boolean]; // no label displayed + type T9 = [number, `${any}wontfly`: boolean]; // no label displayed + type T11 = [number, `${"a" | "b"}wontfly`: boolean]; // no label displayed + type T12 = [number, `${unknown}wontfly`: boolean]; // error + ~~~~~~~ +!!! error TS2322: Type 'unknown' is not assignable to type 'string | number | bigint | boolean | null | undefined'. + + type MakeTuple1 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; + type MakeTuple2 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; // error + ~~ +!!! error TS2322: Type 'T1' is not assignable to type 'string | number | bigint | boolean | null | undefined'. +!!! related TS2208 instantiableTupleLabels1.ts:18:17: This type parameter might need an `extends string | number | bigint | boolean | null | undefined` constraint. + ~~ +!!! error TS2322: Type 'T2' is not assignable to type 'string | number | bigint | boolean | null | undefined'. +!!! related TS2208 instantiableTupleLabels1.ts:18:21: This type parameter might need an `extends string | number | bigint | boolean | null | undefined` constraint. + + type T13 = MakeTuple1<"awesome", "tail">; + type T14 = MakeTuple1; + type T15 = MakeTuple1<"a" | "b", "tail">; + \ No newline at end of file diff --git a/tests/baselines/reference/instantiableTupleLabels1.js b/tests/baselines/reference/instantiableTupleLabels1.js new file mode 100644 index 0000000000000..41151e7298ae0 --- /dev/null +++ b/tests/baselines/reference/instantiableTupleLabels1.js @@ -0,0 +1,49 @@ +//// [tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts] //// + +//// [instantiableTupleLabels1.ts] +type T1 = [`wow`: boolean]; +type T2 = [number, `wow`: boolean]; +type T3 = [number, ...`wow`: boolean[]]; +type T4 = [number, `wow`: ...boolean[]]; // error + +type Prefix = 'pre'; + +type T5 = [`${Prefix}wow`: boolean]; +type T6 = [number, `${Prefix}wow`: boolean]; +type T7 = [number, ...`${Prefix}wow`: boolean[]]; + +type T8 = [number, `${never}wontfly`: boolean]; // no label displayed +type T9 = [number, `${any}wontfly`: boolean]; // no label displayed +type T11 = [number, `${"a" | "b"}wontfly`: boolean]; // no label displayed +type T12 = [number, `${unknown}wontfly`: boolean]; // error + +type MakeTuple1 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; +type MakeTuple2 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; // error + +type T13 = MakeTuple1<"awesome", "tail">; +type T14 = MakeTuple1; +type T15 = MakeTuple1<"a" | "b", "tail">; + + +//// [instantiableTupleLabels1.js] +"use strict"; + + +//// [instantiableTupleLabels1.d.ts] +type T1 = [`wow`: boolean]; +type T2 = [number, `wow`: boolean]; +type T3 = [number, ...`wow`: boolean[]]; +type T4 = [number, `wow`: ...boolean[]]; +type Prefix = 'pre'; +type T5 = [`${Prefix}wow`: boolean]; +type T6 = [number, `${Prefix}wow`: boolean]; +type T7 = [number, ...`${Prefix}wow`: boolean[]]; +type T8 = [number, `${never}wontfly`: boolean]; +type T9 = [number, `${any}wontfly`: boolean]; +type T11 = [number, `${"a" | "b"}wontfly`: boolean]; +type T12 = [number, `${unknown}wontfly`: boolean]; +type MakeTuple1 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; +type MakeTuple2 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; +type T13 = MakeTuple1<"awesome", "tail">; +type T14 = MakeTuple1; +type T15 = MakeTuple1<"a" | "b", "tail">; diff --git a/tests/baselines/reference/instantiableTupleLabels1.symbols b/tests/baselines/reference/instantiableTupleLabels1.symbols new file mode 100644 index 0000000000000..35e2598339d35 --- /dev/null +++ b/tests/baselines/reference/instantiableTupleLabels1.symbols @@ -0,0 +1,68 @@ +//// [tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts] //// + +=== instantiableTupleLabels1.ts === +type T1 = [`wow`: boolean]; +>T1 : Symbol(T1, Decl(instantiableTupleLabels1.ts, 0, 0)) + +type T2 = [number, `wow`: boolean]; +>T2 : Symbol(T2, Decl(instantiableTupleLabels1.ts, 0, 27)) + +type T3 = [number, ...`wow`: boolean[]]; +>T3 : Symbol(T3, Decl(instantiableTupleLabels1.ts, 1, 35)) + +type T4 = [number, `wow`: ...boolean[]]; // error +>T4 : Symbol(T4, Decl(instantiableTupleLabels1.ts, 2, 40)) + +type Prefix = 'pre'; +>Prefix : Symbol(Prefix, Decl(instantiableTupleLabels1.ts, 3, 40)) + +type T5 = [`${Prefix}wow`: boolean]; +>T5 : Symbol(T5, Decl(instantiableTupleLabels1.ts, 5, 20)) +>Prefix : Symbol(Prefix, Decl(instantiableTupleLabels1.ts, 3, 40)) + +type T6 = [number, `${Prefix}wow`: boolean]; +>T6 : Symbol(T6, Decl(instantiableTupleLabels1.ts, 7, 36)) +>Prefix : Symbol(Prefix, Decl(instantiableTupleLabels1.ts, 3, 40)) + +type T7 = [number, ...`${Prefix}wow`: boolean[]]; +>T7 : Symbol(T7, Decl(instantiableTupleLabels1.ts, 8, 44)) +>Prefix : Symbol(Prefix, Decl(instantiableTupleLabels1.ts, 3, 40)) + +type T8 = [number, `${never}wontfly`: boolean]; // no label displayed +>T8 : Symbol(T8, Decl(instantiableTupleLabels1.ts, 9, 49)) + +type T9 = [number, `${any}wontfly`: boolean]; // no label displayed +>T9 : Symbol(T9, Decl(instantiableTupleLabels1.ts, 11, 47)) + +type T11 = [number, `${"a" | "b"}wontfly`: boolean]; // no label displayed +>T11 : Symbol(T11, Decl(instantiableTupleLabels1.ts, 12, 45)) + +type T12 = [number, `${unknown}wontfly`: boolean]; // error +>T12 : Symbol(T12, Decl(instantiableTupleLabels1.ts, 13, 52)) + +type MakeTuple1 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; +>MakeTuple1 : Symbol(MakeTuple1, Decl(instantiableTupleLabels1.ts, 14, 50)) +>T1 : Symbol(T1, Decl(instantiableTupleLabels1.ts, 16, 16)) +>T2 : Symbol(T2, Decl(instantiableTupleLabels1.ts, 16, 34)) +>T1 : Symbol(T1, Decl(instantiableTupleLabels1.ts, 16, 16)) +>T2 : Symbol(T2, Decl(instantiableTupleLabels1.ts, 16, 34)) + +type MakeTuple2 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; // error +>MakeTuple2 : Symbol(MakeTuple2, Decl(instantiableTupleLabels1.ts, 16, 117)) +>T1 : Symbol(T1, Decl(instantiableTupleLabels1.ts, 17, 16)) +>T2 : Symbol(T2, Decl(instantiableTupleLabels1.ts, 17, 19)) +>T1 : Symbol(T1, Decl(instantiableTupleLabels1.ts, 17, 16)) +>T2 : Symbol(T2, Decl(instantiableTupleLabels1.ts, 17, 19)) + +type T13 = MakeTuple1<"awesome", "tail">; +>T13 : Symbol(T13, Decl(instantiableTupleLabels1.ts, 17, 87)) +>MakeTuple1 : Symbol(MakeTuple1, Decl(instantiableTupleLabels1.ts, 14, 50)) + +type T14 = MakeTuple1; +>T14 : Symbol(T14, Decl(instantiableTupleLabels1.ts, 19, 41)) +>MakeTuple1 : Symbol(MakeTuple1, Decl(instantiableTupleLabels1.ts, 14, 50)) + +type T15 = MakeTuple1<"a" | "b", "tail">; +>T15 : Symbol(T15, Decl(instantiableTupleLabels1.ts, 20, 35)) +>MakeTuple1 : Symbol(MakeTuple1, Decl(instantiableTupleLabels1.ts, 14, 50)) + diff --git a/tests/baselines/reference/instantiableTupleLabels1.types b/tests/baselines/reference/instantiableTupleLabels1.types new file mode 100644 index 0000000000000..e0e128ed4144a --- /dev/null +++ b/tests/baselines/reference/instantiableTupleLabels1.types @@ -0,0 +1,54 @@ +//// [tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts] //// + +=== instantiableTupleLabels1.ts === +type T1 = [`wow`: boolean]; +>T1 : [wow: boolean] + +type T2 = [number, `wow`: boolean]; +>T2 : [number, wow: boolean] + +type T3 = [number, ...`wow`: boolean[]]; +>T3 : [number, ...wow: boolean[]] + +type T4 = [number, `wow`: ...boolean[]]; // error +>T4 : [number, wow: boolean] + +type Prefix = 'pre'; +>Prefix : "pre" + +type T5 = [`${Prefix}wow`: boolean]; +>T5 : [prewow: boolean] + +type T6 = [number, `${Prefix}wow`: boolean]; +>T6 : [number, prewow: boolean] + +type T7 = [number, ...`${Prefix}wow`: boolean[]]; +>T7 : [number, ...prewow: boolean[]] + +type T8 = [number, `${never}wontfly`: boolean]; // no label displayed +>T8 : [number, boolean] + +type T9 = [number, `${any}wontfly`: boolean]; // no label displayed +>T9 : [number, boolean] + +type T11 = [number, `${"a" | "b"}wontfly`: boolean]; // no label displayed +>T11 : [number, boolean] + +type T12 = [number, `${unknown}wontfly`: boolean]; // error +>T12 : [number, boolean] + +type MakeTuple1 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; +>MakeTuple1 : MakeTuple1 + +type MakeTuple2 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; // error +>MakeTuple2 : MakeTuple2 + +type T13 = MakeTuple1<"awesome", "tail">; +>T13 : [number, second-awesome: string, ...rest-tail: boolean[]] + +type T14 = MakeTuple1; +>T14 : [number, string, ...rest-tail: boolean[]] + +type T15 = MakeTuple1<"a" | "b", "tail">; +>T15 : [number, string, ...rest-tail: boolean[]] + diff --git a/tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts b/tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts new file mode 100644 index 0000000000000..710fc0d24f06d --- /dev/null +++ b/tests/cases/conformance/types/tuple/instantiableTupleLabels1.ts @@ -0,0 +1,25 @@ +// @strict: true +// @declaration: true + +type T1 = [`wow`: boolean]; +type T2 = [number, `wow`: boolean]; +type T3 = [number, ...`wow`: boolean[]]; +type T4 = [number, `wow`: ...boolean[]]; // error + +type Prefix = 'pre'; + +type T5 = [`${Prefix}wow`: boolean]; +type T6 = [number, `${Prefix}wow`: boolean]; +type T7 = [number, ...`${Prefix}wow`: boolean[]]; + +type T8 = [number, `${never}wontfly`: boolean]; // no label displayed +type T9 = [number, `${any}wontfly`: boolean]; // no label displayed +type T11 = [number, `${"a" | "b"}wontfly`: boolean]; // no label displayed +type T12 = [number, `${unknown}wontfly`: boolean]; // error + +type MakeTuple1 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; +type MakeTuple2 = [number, `second-${T1}`: string, ...`rest-${T2}`: boolean[]]; // error + +type T13 = MakeTuple1<"awesome", "tail">; +type T14 = MakeTuple1; +type T15 = MakeTuple1<"a" | "b", "tail">;