diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bdf2dff585a47..166b50ce8b3d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6876,21 +6876,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const arity = getTypeReferenceArity(type); const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context); if (tupleConstituentNodes) { - if ((type.target as TupleType).labeledElementDeclarations) { - for (let i = 0; i < tupleConstituentNodes.length; i++) { - const flags = (type.target as TupleType).elementFlags[i]; + const { labeledElementDeclarations } = type.target as TupleType; + for (let i = 0; i < tupleConstituentNodes.length; i++) { + const flags = (type.target as TupleType).elementFlags[i]; + const labeledElementDeclaration = labeledElementDeclarations?.[i]; + + if (labeledElementDeclaration) { tupleConstituentNodes[i] = factory.createNamedTupleMember( flags & ElementFlags.Variable ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined, - factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel((type.target as TupleType).labeledElementDeclarations![i]))), + factory.createIdentifier(unescapeLeadingUnderscores(getTupleElementLabel(labeledElementDeclaration))), flags & ElementFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined, flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i] ); } - } - else { - for (let i = 0; i < Math.min(arity, tupleConstituentNodes.length); i++) { - const flags = (type.target as TupleType).elementFlags[i]; + else { tupleConstituentNodes[i] = flags & ElementFlags.Variable ? factory.createRestTypeNode(flags & ElementFlags.Rest ? factory.createArrayTypeNode(tupleConstituentNodes[i]) : tupleConstituentNodes[i]) : flags & ElementFlags.Optional ? factory.createOptionalTypeNode(tupleConstituentNodes[i]) : @@ -12636,19 +12636,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getExpandedParameters(sig: Signature, skipUnionExpanding?: boolean): readonly (readonly Symbol[])[] { if (signatureHasRestParameter(sig)) { const restIndex = sig.parameters.length - 1; + const restName = sig.parameters[restIndex].escapedName; const restType = getTypeOfSymbol(sig.parameters[restIndex]); if (isTupleType(restType)) { - return [expandSignatureParametersWithTupleMembers(restType, restIndex)]; + return [expandSignatureParametersWithTupleMembers(restType, restIndex, restName)]; } else if (!skipUnionExpanding && restType.flags & TypeFlags.Union && every((restType as UnionType).types, isTupleType)) { - return map((restType as UnionType).types, t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex)); + return map((restType as UnionType).types, t => expandSignatureParametersWithTupleMembers(t as TupleTypeReference, restIndex, restName)); } } return [sig.parameters]; - function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number) { - const elementTypes = getElementTypes(restType); - const associatedNames = getUniqAssociatedNamesFromTupleType(restType); + function expandSignatureParametersWithTupleMembers(restType: TupleTypeReference, restIndex: number, restName: __String) { + const elementTypes = getTypeArguments(restType); + const associatedNames = getUniqAssociatedNamesFromTupleType(restType, restName); const restParams = map(elementTypes, (t, i) => { // Lookup the label from the individual tuple passed in before falling back to the signature `rest` parameter name const name = associatedNames && associatedNames[i] ? associatedNames[i] : @@ -12663,10 +12664,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return concatenate(sig.parameters.slice(0, restIndex), restParams); } - function getUniqAssociatedNamesFromTupleType(type: TupleTypeReference) { + function getUniqAssociatedNamesFromTupleType(type: TupleTypeReference, restName: __String) { const associatedNamesMap = new Map<__String, number>(); - return map(type.target.labeledElementDeclarations, labeledElement => { - const name = getTupleElementLabel(labeledElement); + return map(type.target.labeledElementDeclarations, (labeledElement, i) => { + const name = getTupleElementLabel(labeledElement, i, restName); const prevCounter = associatedNamesMap.get(name); if (prevCounter === undefined) { associatedNamesMap.set(name, 1); @@ -15934,8 +15935,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return readonly ? globalReadonlyArrayType : globalArrayType; } const elementFlags = map((node as TupleTypeNode).elements, getTupleElementFlags); - const missingName = some((node as TupleTypeNode).elements, e => e.kind !== SyntaxKind.NamedTupleMember); - return getTupleTargetType(elementFlags, readonly, /*associatedNames*/ missingName ? undefined : (node as TupleTypeNode).elements as readonly NamedTupleMember[]); + return getTupleTargetType(elementFlags, readonly, map((node as TupleTypeNode).elements, memberIfLabeledElementDeclaration)); + } + + function memberIfLabeledElementDeclaration(member: Node): NamedTupleMember | ParameterDeclaration | undefined { + return isNamedTupleMember(member) || isParameter(member) ? member : undefined; } // Return true if the given type reference node is directly aliased or if it needs to be deferred @@ -16025,21 +16029,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return isTypeOperatorNode(node) && node.operator === SyntaxKind.ReadonlyKeyword; } - function createTupleType(elementTypes: readonly Type[], elementFlags?: readonly ElementFlags[], readonly = false, namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]) { + function createTupleType(elementTypes: readonly Type[], elementFlags?: readonly ElementFlags[], readonly = false, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[] = []) { const tupleTarget = getTupleTargetType(elementFlags || map(elementTypes, _ => ElementFlags.Required), readonly, namedMemberDeclarations); return tupleTarget === emptyGenericType ? emptyObjectType : elementTypes.length ? createNormalizedTypeReference(tupleTarget, elementTypes) : tupleTarget; } - function getTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]): GenericType { + function getTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]): GenericType { if (elementFlags.length === 1 && elementFlags[0] & ElementFlags.Rest) { // [...X[]] is equivalent to just X[] return readonly ? globalReadonlyArrayType : globalArrayType; } + const memberIds = mapDefined(namedMemberDeclarations, node => node ? getNodeId(node) : undefined); const key = map(elementFlags, f => f & ElementFlags.Required ? "#" : f & ElementFlags.Optional ? "?" : f & ElementFlags.Rest ? "." : "*").join() + (readonly ? "R" : "") + - (namedMemberDeclarations && namedMemberDeclarations.length ? "," + map(namedMemberDeclarations, getNodeId).join(",") : ""); + (memberIds.length ? "," + memberIds.join(",") : ""); let type = tupleTypes.get(key); if (!type) { tupleTypes.set(key, type = createTupleTargetType(elementFlags, readonly, namedMemberDeclarations)); @@ -16054,7 +16059,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // // Note that the generic type created by this function has no symbol associated with it. The same // is true for each of the synthesized type parameters. - function createTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration)[] | undefined): TupleType { + function createTupleTargetType(elementFlags: readonly ElementFlags[], readonly: boolean, namedMemberDeclarations: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]): TupleType { const arity = elementFlags.length; const minLength = countWhere(elementFlags, f => !!(f & (ElementFlags.Required | ElementFlags.Variadic))); let typeParameters: TypeParameter[] | undefined; @@ -16136,7 +16141,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // In either layout, zero or more generic variadic elements may be present at any location. const expandedTypes: Type[] = []; const expandedFlags: ElementFlags[] = []; - let expandedDeclarations: (NamedTupleMember | ParameterDeclaration)[] | undefined = []; + const expandedDeclarations: (NamedTupleMember | ParameterDeclaration | undefined)[] = []; let lastRequiredIndex = -1; let firstRestIndex = -1; let lastOptionalOrRestIndex = -1; @@ -16179,7 +16184,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { (t, i) => expandedFlags[firstRestIndex + i] & ElementFlags.Variadic ? getIndexedAccessType(t, numberType) : t)); expandedTypes.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); expandedFlags.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); - expandedDeclarations?.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); + expandedDeclarations.splice(firstRestIndex + 1, lastOptionalOrRestIndex - firstRestIndex); } const tupleTarget = getTupleTargetType(expandedFlags, target.readonly, expandedDeclarations); return tupleTarget === emptyGenericType ? emptyObjectType : @@ -16198,12 +16203,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } expandedTypes.push(flags & ElementFlags.Optional ? addOptionality(type, /*isProperty*/ true) : type); expandedFlags.push(flags); - if (expandedDeclarations && declaration) { - expandedDeclarations.push(declaration); - } - else { - expandedDeclarations = undefined; - } + expandedDeclarations.push(declaration); } } @@ -34793,7 +34793,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return type; } - function getTupleElementLabel(d: ParameterDeclaration | NamedTupleMember) { + 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) { + if (!d) { + return `${restParameterName}_${index}` as __String; + } Debug.assert(isIdentifier(d.name)); // Parameter declarations could be binding patterns, but we only allow identifier names return d.name.escapedText; } @@ -34808,7 +34813,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isTupleType(restType)) { const associatedNames = ((restType as TypeReference).target as TupleType).labeledElementDeclarations; const index = pos - paramCount; - return associatedNames && getTupleElementLabel(associatedNames[index]) || restParameter.escapedName + "_" + index as __String; + return getTupleElementLabel(associatedNames?.[index], index, restParameter.escapedName); } return restParameter.escapedName; } @@ -38821,12 +38826,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementTypes = node.elements; let seenOptionalElement = false; let seenRestElement = false; - const hasNamedElement = some(elementTypes, isNamedTupleMember); for (const e of elementTypes) { - if (e.kind !== SyntaxKind.NamedTupleMember && hasNamedElement) { - grammarErrorOnNode(e, Diagnostics.Tuple_members_must_all_have_names_or_all_not_have_names); - break; - } const flags = getTupleElementFlags(e); if (flags & ElementFlags.Variadic) { const type = getTypeFromTypeNode((e as RestTypeNode | NamedTupleMember).type); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 65ccc4cb18fdc..b89eeeb8d5b9f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4237,10 +4237,6 @@ "category": "Error", "code": 5083 }, - "Tuple members must all have names or all not have names.": { - "category": "Error", - "code": 5084 - }, "A tuple member cannot be both optional and rest.": { "category": "Error", "code": 5085 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 008d4d710bea5..330f05107ba90 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6430,7 +6430,7 @@ export interface TupleType extends GenericType { hasRestElement: boolean; combinedFlags: ElementFlags; readonly: boolean; - labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]; + labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]; } export interface TupleTypeReference extends TypeReference { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 56c4b49ff6df2..f25295c367d2c 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -6948,7 +6948,7 @@ declare namespace ts { hasRestElement: boolean; combinedFlags: ElementFlags; readonly: boolean; - labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]; + labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]; } interface TupleTypeReference extends TypeReference { target: TupleType; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2b642a091ce2e..5e3133bf0f733 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2895,7 +2895,7 @@ declare namespace ts { hasRestElement: boolean; combinedFlags: ElementFlags; readonly: boolean; - labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration)[]; + labeledElementDeclarations?: readonly (NamedTupleMember | ParameterDeclaration | undefined)[]; } interface TupleTypeReference extends TypeReference { target: TupleType; diff --git a/tests/baselines/reference/genericRestParameters2.types b/tests/baselines/reference/genericRestParameters2.types index 6ad95193ba359..3fb55995e1c12 100644 --- a/tests/baselines/reference/genericRestParameters2.types +++ b/tests/baselines/reference/genericRestParameters2.types @@ -444,7 +444,7 @@ type T05 = Parameters<(x: string, ...args: T) => void>; >args : T type T06 = T05<[number, ...boolean[]]>; ->T06 : [string, number, ...boolean[]] +>T06 : [x: string, number, ...boolean[]] type P1 = T extends (head: infer A, ...tail: infer B) => any ? { head: A, tail: B } : any[]; >P1 : P1 diff --git a/tests/baselines/reference/genericRestParameters3.types b/tests/baselines/reference/genericRestParameters3.types index 7b5612921d0ec..f68aff7833e40 100644 --- a/tests/baselines/reference/genericRestParameters3.types +++ b/tests/baselines/reference/genericRestParameters3.types @@ -264,19 +264,19 @@ ff2 = ff1; function ff3(s1: (...args: [x: string, ...rest: A | [number]]) => void, s2: (x: string, ...rest: A | [number]) => void) { >ff3 : (s1: (...args: [x: string, ...rest: A | [number]]) => void, s2: (x: string, ...rest: A | [number]) => void) => void >s1 : (...args: [x: string, ...rest: A | [number]]) => void ->args : [string, number] | [x: string, ...rest: A] +>args : [x: string, number] | [x: string, ...rest: A] >s2 : (x: string, ...rest: A | [number]) => void >x : string >rest : [number] | A s1 = s2; >s1 = s2 : (x: string, ...rest: [number] | A) => void ->s1 : (...args: [string, number] | [x: string, ...rest: A]) => void +>s1 : (...args: [x: string, number] | [x: string, ...rest: A]) => void >s2 : (x: string, ...rest: [number] | A) => void s2 = s1; ->s2 = s1 : (...args: [string, number] | [x: string, ...rest: A]) => void +>s2 = s1 : (...args: [x: string, number] | [x: string, ...rest: A]) => void >s2 : (x: string, ...rest: [number] | A) => void ->s1 : (...args: [string, number] | [x: string, ...rest: A]) => void +>s1 : (...args: [x: string, number] | [x: string, ...rest: A]) => void } diff --git a/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types b/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types index 79354eccf2ab4..47027e0428628 100644 --- a/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types +++ b/tests/baselines/reference/inferTypesWithFixedTupleExtendsAtVariadicPosition.types @@ -40,7 +40,7 @@ type SubTup2VariadicAndRest = T extends [ : never; type SubTup2VariadicAndRestTest = SubTup2VariadicAndRest<[a: 0, b: 1, ...c: 2[]]>; ->SubTup2VariadicAndRestTest : [0, 1, 2] +>SubTup2VariadicAndRestTest : [a: 0, b: 1, 2] type SubTup2TrailingVariadic = T extends [ >SubTup2TrailingVariadic : SubTup2TrailingVariadic @@ -67,7 +67,7 @@ type SubTup2RestAndTrailingVariadic2 = T extends [ : never; type SubTup2RestAndTrailingVariadic2Test = SubTup2RestAndTrailingVariadic2<[...a: 0[], b: 1, c: 2]>; ->SubTup2RestAndTrailingVariadic2Test : [0, 1, 2] +>SubTup2RestAndTrailingVariadic2Test : [0, b: 1, c: 2] type SubTup2VariadicWithLeadingFixedElements = T extends [ >SubTup2VariadicWithLeadingFixedElements : SubTup2VariadicWithLeadingFixedElements diff --git a/tests/baselines/reference/namedTupleMembersErrors.errors.txt b/tests/baselines/reference/namedTupleMembersErrors.errors.txt index 3cb737741448f..a8cdf98ca30b8 100644 --- a/tests/baselines/reference/namedTupleMembersErrors.errors.txt +++ b/tests/baselines/reference/namedTupleMembersErrors.errors.txt @@ -1,9 +1,3 @@ -namedTupleMembersErrors.ts(1,41): error TS5084: Tuple members must all have names or all not have names. -namedTupleMembersErrors.ts(2,25): error TS5084: Tuple members must all have names or all not have names. -namedTupleMembersErrors.ts(4,32): error TS5084: Tuple members must all have names or all not have names. -namedTupleMembersErrors.ts(5,22): error TS5084: Tuple members must all have names or all not have names. -namedTupleMembersErrors.ts(7,32): error TS5084: Tuple members must all have names or all not have names. -namedTupleMembersErrors.ts(8,22): error TS5084: Tuple members must all have names or all not have names. namedTupleMembersErrors.ts(10,29): error TS5086: A labeled tuple element is declared as optional with a question mark after the name and before the colon, rather than after the type. namedTupleMembersErrors.ts(12,46): error TS5087: A labeled tuple element is declared as rest with a '...' before the name, rather than before the type. namedTupleMembersErrors.ts(14,49): error TS5087: A labeled tuple element is declared as rest with a '...' before the name, rather than before the type. @@ -14,27 +8,15 @@ namedTupleMembersErrors.ts(20,13): error TS2456: Type alias 'RecusiveRestUnlabel namedTupleMembersErrors.ts(21,13): error TS2456: Type alias 'RecusiveRest' circularly references itself. -==== namedTupleMembersErrors.ts (14 errors) ==== - export type Segment1 = [length: number, number]; // partially named, disallowed - ~~~~~~ -!!! error TS5084: Tuple members must all have names or all not have names. - export type Segment2 = [number, size: number]; // partially named, disallowed - ~~~~~~ -!!! error TS5084: Tuple members must all have names or all not have names. +==== namedTupleMembersErrors.ts (8 errors) ==== + export type Segment1 = [length: number, number]; + export type Segment2 = [number, size: number]; - export type List = [item: any, ...any]; // partially named, disallowed - ~~~~~~ -!!! error TS5084: Tuple members must all have names or all not have names. - export type List2 = [any, ...remainder: any]; // partially named, disallowed - ~~~ -!!! error TS5084: Tuple members must all have names or all not have names. + export type List = [item: any, ...any]; + export type List2 = [any, ...remainder: any]; - export type Pair = [item: any, any?]; // partially named, disallowed - ~~~~ -!!! error TS5084: Tuple members must all have names or all not have names. - export type Pair2 = [any, last?: any]; // partially named, disallowed - ~~~ -!!! error TS5084: Tuple members must all have names or all not have names. + export type Pair = [item: any, any?]; + export type Pair2 = [any, last?: any]; export type Opt = [element: string?]; // question mark on element disallowed ~~~~~~~ diff --git a/tests/baselines/reference/namedTupleMembersErrors.js b/tests/baselines/reference/namedTupleMembersErrors.js index caa410346fb82..b31332e4a2cbf 100644 --- a/tests/baselines/reference/namedTupleMembersErrors.js +++ b/tests/baselines/reference/namedTupleMembersErrors.js @@ -1,14 +1,14 @@ //// [tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts] //// //// [namedTupleMembersErrors.ts] -export type Segment1 = [length: number, number]; // partially named, disallowed -export type Segment2 = [number, size: number]; // partially named, disallowed +export type Segment1 = [length: number, number]; +export type Segment2 = [number, size: number]; -export type List = [item: any, ...any]; // partially named, disallowed -export type List2 = [any, ...remainder: any]; // partially named, disallowed +export type List = [item: any, ...any]; +export type List2 = [any, ...remainder: any]; -export type Pair = [item: any, any?]; // partially named, disallowed -export type Pair2 = [any, last?: any]; // partially named, disallowed +export type Pair = [item: any, any?]; +export type Pair2 = [any, last?: any]; export type Opt = [element: string?]; // question mark on element disallowed diff --git a/tests/baselines/reference/namedTupleMembersErrors.symbols b/tests/baselines/reference/namedTupleMembersErrors.symbols index 19bfa42afeb83..865bfc9842e50 100644 --- a/tests/baselines/reference/namedTupleMembersErrors.symbols +++ b/tests/baselines/reference/namedTupleMembersErrors.symbols @@ -1,22 +1,22 @@ //// [tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts] //// === namedTupleMembersErrors.ts === -export type Segment1 = [length: number, number]; // partially named, disallowed +export type Segment1 = [length: number, number]; >Segment1 : Symbol(Segment1, Decl(namedTupleMembersErrors.ts, 0, 0)) -export type Segment2 = [number, size: number]; // partially named, disallowed +export type Segment2 = [number, size: number]; >Segment2 : Symbol(Segment2, Decl(namedTupleMembersErrors.ts, 0, 48)) -export type List = [item: any, ...any]; // partially named, disallowed +export type List = [item: any, ...any]; >List : Symbol(List, Decl(namedTupleMembersErrors.ts, 1, 46)) -export type List2 = [any, ...remainder: any]; // partially named, disallowed +export type List2 = [any, ...remainder: any]; >List2 : Symbol(List2, Decl(namedTupleMembersErrors.ts, 3, 39)) -export type Pair = [item: any, any?]; // partially named, disallowed +export type Pair = [item: any, any?]; >Pair : Symbol(Pair, Decl(namedTupleMembersErrors.ts, 4, 45)) -export type Pair2 = [any, last?: any]; // partially named, disallowed +export type Pair2 = [any, last?: any]; >Pair2 : Symbol(Pair2, Decl(namedTupleMembersErrors.ts, 6, 37)) export type Opt = [element: string?]; // question mark on element disallowed diff --git a/tests/baselines/reference/namedTupleMembersErrors.types b/tests/baselines/reference/namedTupleMembersErrors.types index 060753947189c..46f0bc4ca60a4 100644 --- a/tests/baselines/reference/namedTupleMembersErrors.types +++ b/tests/baselines/reference/namedTupleMembersErrors.types @@ -1,23 +1,23 @@ //// [tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts] //// === namedTupleMembersErrors.ts === -export type Segment1 = [length: number, number]; // partially named, disallowed ->Segment1 : [number, number] +export type Segment1 = [length: number, number]; +>Segment1 : [length: number, number] -export type Segment2 = [number, size: number]; // partially named, disallowed ->Segment2 : [number, number] +export type Segment2 = [number, size: number]; +>Segment2 : [number, size: number] -export type List = [item: any, ...any]; // partially named, disallowed ->List : [any, ...any[]] +export type List = [item: any, ...any]; +>List : [item: any, ...any[]] -export type List2 = [any, ...remainder: any]; // partially named, disallowed ->List2 : [any, ...any[]] +export type List2 = [any, ...remainder: any]; +>List2 : [any, ...remainder: any[]] -export type Pair = [item: any, any?]; // partially named, disallowed ->Pair : [any, any?] +export type Pair = [item: any, any?]; +>Pair : [item: any, any?] -export type Pair2 = [any, last?: any]; // partially named, disallowed ->Pair2 : [any, any?] +export type Pair2 = [any, last?: any]; +>Pair2 : [any, last?: any] export type Opt = [element: string?]; // question mark on element disallowed >Opt : [element: string] diff --git a/tests/baselines/reference/partiallyNamedTuples.js b/tests/baselines/reference/partiallyNamedTuples.js new file mode 100644 index 0000000000000..8d497fe5dd55c --- /dev/null +++ b/tests/baselines/reference/partiallyNamedTuples.js @@ -0,0 +1,95 @@ +//// [tests/cases/conformance/types/tuple/named/partiallyNamedTuples.ts] //// + +//// [partiallyNamedTuples.ts] +type NamedAndAnonymous = [a: string, number]; + +function fa1(...args: NamedAndAnonymous) {} +function fa2(a: NamedAndAnonymous, ...args: NamedAndAnonymous) {} + +type NamedAnonymousMixed = [a: string, number, c: number, NamedAndAnonymous]; + +function fb1(...args: NamedAnonymousMixed) {} +function fb2(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed) {} +function fb3(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed[3]) {} + +type ToAnonymousTuple = { + [K in keyof T]: [K, T[K], keyof T, T]; +}; + +type AnonymousToAnonymous = ToAnonymousTuple<[boolean, number]>; +type MixedToAnonymous = ToAnonymousTuple<[boolean, second: number]>; +type NamedToAnonymous = ToAnonymousTuple<[first: boolean, second: number]>; + +type ToMixedTuple = { + [K in keyof T]: [K, second: T[K], keyof T, fourth: T]; +}; + +type AnonymousToMixed = ToMixedTuple<[boolean, number]>; +type MixedToMixed = ToMixedTuple<[boolean, second: number]>; +type NamedToMixed = ToMixedTuple<[first: boolean, second: number]>; + +type MixedSpread = [first: boolean, ...[second: string]]; + +type ConditionalTuple = [ + first: boolean, + ...(0 extends 0 ? [second: string] : []) +]; + +type AddMixedConditional = [ + first: boolean, + null, + third: T extends number ? "a" : "b", + ...(T extends 0 ? [fourth: "c"] : []) +]; + +type AddMixedConditionalBoolean = AddMixedConditional; +type AddMixedConditionalLiteral = AddMixedConditional<0>; +type AddMixedConditionalNumberPrimitive = AddMixedConditional; + +declare function test( + arg: [ + ...{ + [K in keyof T]: { + type: T[K]; + }; + } + ] +): T; + +declare const input: [first: { type: number }, { type: string }]; + +const output = test(input); + + +//// [partiallyNamedTuples.js] +function fa1() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } +} +function fa2(a) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } +} +function fb1() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } +} +function fb2(a) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } +} +function fb3(a) { + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } +} +var output = test(input); diff --git a/tests/baselines/reference/partiallyNamedTuples.symbols b/tests/baselines/reference/partiallyNamedTuples.symbols new file mode 100644 index 0000000000000..89e2e81b463f5 --- /dev/null +++ b/tests/baselines/reference/partiallyNamedTuples.symbols @@ -0,0 +1,164 @@ +//// [tests/cases/conformance/types/tuple/named/partiallyNamedTuples.ts] //// + +=== partiallyNamedTuples.ts === +type NamedAndAnonymous = [a: string, number]; +>NamedAndAnonymous : Symbol(NamedAndAnonymous, Decl(partiallyNamedTuples.ts, 0, 0)) + +function fa1(...args: NamedAndAnonymous) {} +>fa1 : Symbol(fa1, Decl(partiallyNamedTuples.ts, 0, 45)) +>args : Symbol(args, Decl(partiallyNamedTuples.ts, 2, 13)) +>NamedAndAnonymous : Symbol(NamedAndAnonymous, Decl(partiallyNamedTuples.ts, 0, 0)) + +function fa2(a: NamedAndAnonymous, ...args: NamedAndAnonymous) {} +>fa2 : Symbol(fa2, Decl(partiallyNamedTuples.ts, 2, 43)) +>a : Symbol(a, Decl(partiallyNamedTuples.ts, 3, 13)) +>NamedAndAnonymous : Symbol(NamedAndAnonymous, Decl(partiallyNamedTuples.ts, 0, 0)) +>args : Symbol(args, Decl(partiallyNamedTuples.ts, 3, 34)) +>NamedAndAnonymous : Symbol(NamedAndAnonymous, Decl(partiallyNamedTuples.ts, 0, 0)) + +type NamedAnonymousMixed = [a: string, number, c: number, NamedAndAnonymous]; +>NamedAnonymousMixed : Symbol(NamedAnonymousMixed, Decl(partiallyNamedTuples.ts, 3, 65)) +>NamedAndAnonymous : Symbol(NamedAndAnonymous, Decl(partiallyNamedTuples.ts, 0, 0)) + +function fb1(...args: NamedAnonymousMixed) {} +>fb1 : Symbol(fb1, Decl(partiallyNamedTuples.ts, 5, 77)) +>args : Symbol(args, Decl(partiallyNamedTuples.ts, 7, 13)) +>NamedAnonymousMixed : Symbol(NamedAnonymousMixed, Decl(partiallyNamedTuples.ts, 3, 65)) + +function fb2(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed) {} +>fb2 : Symbol(fb2, Decl(partiallyNamedTuples.ts, 7, 45)) +>a : Symbol(a, Decl(partiallyNamedTuples.ts, 8, 13)) +>NamedAnonymousMixed : Symbol(NamedAnonymousMixed, Decl(partiallyNamedTuples.ts, 3, 65)) +>args : Symbol(args, Decl(partiallyNamedTuples.ts, 8, 36)) +>NamedAnonymousMixed : Symbol(NamedAnonymousMixed, Decl(partiallyNamedTuples.ts, 3, 65)) + +function fb3(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed[3]) {} +>fb3 : Symbol(fb3, Decl(partiallyNamedTuples.ts, 8, 69)) +>a : Symbol(a, Decl(partiallyNamedTuples.ts, 9, 13)) +>NamedAnonymousMixed : Symbol(NamedAnonymousMixed, Decl(partiallyNamedTuples.ts, 3, 65)) +>args : Symbol(args, Decl(partiallyNamedTuples.ts, 9, 36)) +>NamedAnonymousMixed : Symbol(NamedAnonymousMixed, Decl(partiallyNamedTuples.ts, 3, 65)) + +type ToAnonymousTuple = { +>ToAnonymousTuple : Symbol(ToAnonymousTuple, Decl(partiallyNamedTuples.ts, 9, 72)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 11, 22)) + + [K in keyof T]: [K, T[K], keyof T, T]; +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 12, 3)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 11, 22)) +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 12, 3)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 11, 22)) +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 12, 3)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 11, 22)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 11, 22)) + +}; + +type AnonymousToAnonymous = ToAnonymousTuple<[boolean, number]>; +>AnonymousToAnonymous : Symbol(AnonymousToAnonymous, Decl(partiallyNamedTuples.ts, 13, 2)) +>ToAnonymousTuple : Symbol(ToAnonymousTuple, Decl(partiallyNamedTuples.ts, 9, 72)) + +type MixedToAnonymous = ToAnonymousTuple<[boolean, second: number]>; +>MixedToAnonymous : Symbol(MixedToAnonymous, Decl(partiallyNamedTuples.ts, 15, 64)) +>ToAnonymousTuple : Symbol(ToAnonymousTuple, Decl(partiallyNamedTuples.ts, 9, 72)) + +type NamedToAnonymous = ToAnonymousTuple<[first: boolean, second: number]>; +>NamedToAnonymous : Symbol(NamedToAnonymous, Decl(partiallyNamedTuples.ts, 16, 68)) +>ToAnonymousTuple : Symbol(ToAnonymousTuple, Decl(partiallyNamedTuples.ts, 9, 72)) + +type ToMixedTuple = { +>ToMixedTuple : Symbol(ToMixedTuple, Decl(partiallyNamedTuples.ts, 17, 75)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 19, 18)) + + [K in keyof T]: [K, second: T[K], keyof T, fourth: T]; +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 20, 3)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 19, 18)) +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 20, 3)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 19, 18)) +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 20, 3)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 19, 18)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 19, 18)) + +}; + +type AnonymousToMixed = ToMixedTuple<[boolean, number]>; +>AnonymousToMixed : Symbol(AnonymousToMixed, Decl(partiallyNamedTuples.ts, 21, 2)) +>ToMixedTuple : Symbol(ToMixedTuple, Decl(partiallyNamedTuples.ts, 17, 75)) + +type MixedToMixed = ToMixedTuple<[boolean, second: number]>; +>MixedToMixed : Symbol(MixedToMixed, Decl(partiallyNamedTuples.ts, 23, 56)) +>ToMixedTuple : Symbol(ToMixedTuple, Decl(partiallyNamedTuples.ts, 17, 75)) + +type NamedToMixed = ToMixedTuple<[first: boolean, second: number]>; +>NamedToMixed : Symbol(NamedToMixed, Decl(partiallyNamedTuples.ts, 24, 60)) +>ToMixedTuple : Symbol(ToMixedTuple, Decl(partiallyNamedTuples.ts, 17, 75)) + +type MixedSpread = [first: boolean, ...[second: string]]; +>MixedSpread : Symbol(MixedSpread, Decl(partiallyNamedTuples.ts, 25, 67)) + +type ConditionalTuple = [ +>ConditionalTuple : Symbol(ConditionalTuple, Decl(partiallyNamedTuples.ts, 27, 57)) + + first: boolean, + ...(0 extends 0 ? [second: string] : []) +]; + +type AddMixedConditional = [ +>AddMixedConditional : Symbol(AddMixedConditional, Decl(partiallyNamedTuples.ts, 32, 2)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 34, 25)) + + first: boolean, + null, + third: T extends number ? "a" : "b", +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 34, 25)) + + ...(T extends 0 ? [fourth: "c"] : []) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 34, 25)) + +]; + +type AddMixedConditionalBoolean = AddMixedConditional; +>AddMixedConditionalBoolean : Symbol(AddMixedConditionalBoolean, Decl(partiallyNamedTuples.ts, 39, 2)) +>AddMixedConditional : Symbol(AddMixedConditional, Decl(partiallyNamedTuples.ts, 32, 2)) + +type AddMixedConditionalLiteral = AddMixedConditional<0>; +>AddMixedConditionalLiteral : Symbol(AddMixedConditionalLiteral, Decl(partiallyNamedTuples.ts, 41, 63)) +>AddMixedConditional : Symbol(AddMixedConditional, Decl(partiallyNamedTuples.ts, 32, 2)) + +type AddMixedConditionalNumberPrimitive = AddMixedConditional; +>AddMixedConditionalNumberPrimitive : Symbol(AddMixedConditionalNumberPrimitive, Decl(partiallyNamedTuples.ts, 42, 57)) +>AddMixedConditional : Symbol(AddMixedConditional, Decl(partiallyNamedTuples.ts, 32, 2)) + +declare function test( +>test : Symbol(test, Decl(partiallyNamedTuples.ts, 43, 70)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 45, 22)) + + arg: [ +>arg : Symbol(arg, Decl(partiallyNamedTuples.ts, 45, 52)) + + ...{ + [K in keyof T]: { +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 48, 7)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 45, 22)) + + type: T[K]; +>type : Symbol(type, Decl(partiallyNamedTuples.ts, 48, 23)) +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 45, 22)) +>K : Symbol(K, Decl(partiallyNamedTuples.ts, 48, 7)) + + }; + } + ] +): T; +>T : Symbol(T, Decl(partiallyNamedTuples.ts, 45, 22)) + +declare const input: [first: { type: number }, { type: string }]; +>input : Symbol(input, Decl(partiallyNamedTuples.ts, 55, 13)) +>type : Symbol(type, Decl(partiallyNamedTuples.ts, 55, 30)) +>type : Symbol(type, Decl(partiallyNamedTuples.ts, 55, 48)) + +const output = test(input); +>output : Symbol(output, Decl(partiallyNamedTuples.ts, 57, 5)) +>test : Symbol(test, Decl(partiallyNamedTuples.ts, 43, 70)) +>input : Symbol(input, Decl(partiallyNamedTuples.ts, 55, 13)) + diff --git a/tests/baselines/reference/partiallyNamedTuples.types b/tests/baselines/reference/partiallyNamedTuples.types new file mode 100644 index 0000000000000..5f1b72e5e5c90 --- /dev/null +++ b/tests/baselines/reference/partiallyNamedTuples.types @@ -0,0 +1,117 @@ +//// [tests/cases/conformance/types/tuple/named/partiallyNamedTuples.ts] //// + +=== partiallyNamedTuples.ts === +type NamedAndAnonymous = [a: string, number]; +>NamedAndAnonymous : [a: string, number] + +function fa1(...args: NamedAndAnonymous) {} +>fa1 : (a: string, args_1: number) => void +>args : NamedAndAnonymous + +function fa2(a: NamedAndAnonymous, ...args: NamedAndAnonymous) {} +>fa2 : (a: NamedAndAnonymous, a: string, args_1: number) => void +>a : NamedAndAnonymous +>args : NamedAndAnonymous + +type NamedAnonymousMixed = [a: string, number, c: number, NamedAndAnonymous]; +>NamedAnonymousMixed : [a: string, number, c: number, NamedAndAnonymous] + +function fb1(...args: NamedAnonymousMixed) {} +>fb1 : (a: string, args_1: number, c: number, args_3: NamedAndAnonymous) => void +>args : NamedAnonymousMixed + +function fb2(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed) {} +>fb2 : (a: NamedAnonymousMixed, a: string, args_1: number, c: number, args_3: NamedAndAnonymous) => void +>a : NamedAnonymousMixed +>args : NamedAnonymousMixed + +function fb3(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed[3]) {} +>fb3 : (a: NamedAnonymousMixed, a: string, args_1: number) => void +>a : NamedAnonymousMixed +>args : NamedAndAnonymous + +type ToAnonymousTuple = { +>ToAnonymousTuple : ToAnonymousTuple + + [K in keyof T]: [K, T[K], keyof T, T]; +}; + +type AnonymousToAnonymous = ToAnonymousTuple<[boolean, number]>; +>AnonymousToAnonymous : [["0", boolean, keyof [boolean, number], [boolean, number]], ["1", number, keyof [boolean, number], [boolean, number]]] + +type MixedToAnonymous = ToAnonymousTuple<[boolean, second: number]>; +>MixedToAnonymous : [["0", boolean, keyof [boolean, second: number], [boolean, second: number]], second: ["1", number, keyof [boolean, second: number], [boolean, second: number]]] + +type NamedToAnonymous = ToAnonymousTuple<[first: boolean, second: number]>; +>NamedToAnonymous : [first: ["0", boolean, keyof [first: boolean, second: number], [first: boolean, second: number]], second: ["1", number, keyof [first: boolean, second: number], [first: boolean, second: number]]] + +type ToMixedTuple = { +>ToMixedTuple : ToMixedTuple + + [K in keyof T]: [K, second: T[K], keyof T, fourth: T]; +}; + +type AnonymousToMixed = ToMixedTuple<[boolean, number]>; +>AnonymousToMixed : [["0", second: boolean, keyof [boolean, number], fourth: [boolean, number]], ["1", second: number, keyof [boolean, number], fourth: [boolean, number]]] + +type MixedToMixed = ToMixedTuple<[boolean, second: number]>; +>MixedToMixed : [["0", second: boolean, keyof [boolean, second: number], fourth: [boolean, second: number]], second: ["1", second: number, keyof [boolean, second: number], fourth: [boolean, second: number]]] + +type NamedToMixed = ToMixedTuple<[first: boolean, second: number]>; +>NamedToMixed : [first: ["0", second: boolean, keyof [first: boolean, second: number], fourth: [first: boolean, second: number]], second: ["1", second: number, keyof [first: boolean, second: number], fourth: [first: boolean, second: number]]] + +type MixedSpread = [first: boolean, ...[second: string]]; +>MixedSpread : [first: boolean, second: string] + +type ConditionalTuple = [ +>ConditionalTuple : [first: boolean, second: string] + + first: boolean, + ...(0 extends 0 ? [second: string] : []) +]; + +type AddMixedConditional = [ +>AddMixedConditional : [first: boolean, null, third: T extends number ? "a" : "b", ...T extends 0 ? [fourth: "c"] : []] + + first: boolean, + null, + third: T extends number ? "a" : "b", + ...(T extends 0 ? [fourth: "c"] : []) +]; + +type AddMixedConditionalBoolean = AddMixedConditional; +>AddMixedConditionalBoolean : [first: boolean, null, third: "b"] + +type AddMixedConditionalLiteral = AddMixedConditional<0>; +>AddMixedConditionalLiteral : [first: boolean, null, third: "a", fourth: "c"] + +type AddMixedConditionalNumberPrimitive = AddMixedConditional; +>AddMixedConditionalNumberPrimitive : [first: boolean, null, third: "a"] + +declare function test( +>test : (arg: [...{ [K in keyof T]: { type: T[K]; }; }]) => T + + arg: [ +>arg : [...{ [K in keyof T]: { type: T[K]; }; }] + + ...{ + [K in keyof T]: { + type: T[K]; +>type : T[K] + + }; + } + ] +): T; + +declare const input: [first: { type: number }, { type: string }]; +>input : [first: { type: number; }, { type: string; }] +>type : number +>type : string + +const output = test(input); +>output : [first: number, string] +>test(input) : [first: number, string] +>test : (arg: [...{ [K in keyof T]: { type: T[K]; }; }]) => T +>input : [first: { type: number; }, { type: string; }] + diff --git a/tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts b/tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts index 6a1f5a0537085..ecd90aebd7ddd 100644 --- a/tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts +++ b/tests/cases/conformance/types/tuple/named/namedTupleMembersErrors.ts @@ -1,13 +1,13 @@ // @declaration: true -export type Segment1 = [length: number, number]; // partially named, disallowed -export type Segment2 = [number, size: number]; // partially named, disallowed +export type Segment1 = [length: number, number]; +export type Segment2 = [number, size: number]; -export type List = [item: any, ...any]; // partially named, disallowed -export type List2 = [any, ...remainder: any]; // partially named, disallowed +export type List = [item: any, ...any]; +export type List2 = [any, ...remainder: any]; -export type Pair = [item: any, any?]; // partially named, disallowed -export type Pair2 = [any, last?: any]; // partially named, disallowed +export type Pair = [item: any, any?]; +export type Pair2 = [any, last?: any]; export type Opt = [element: string?]; // question mark on element disallowed diff --git a/tests/cases/conformance/types/tuple/named/partiallyNamedTuples.ts b/tests/cases/conformance/types/tuple/named/partiallyNamedTuples.ts new file mode 100644 index 0000000000000..0c6e3752844fd --- /dev/null +++ b/tests/cases/conformance/types/tuple/named/partiallyNamedTuples.ts @@ -0,0 +1,58 @@ +type NamedAndAnonymous = [a: string, number]; + +function fa1(...args: NamedAndAnonymous) {} +function fa2(a: NamedAndAnonymous, ...args: NamedAndAnonymous) {} + +type NamedAnonymousMixed = [a: string, number, c: number, NamedAndAnonymous]; + +function fb1(...args: NamedAnonymousMixed) {} +function fb2(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed) {} +function fb3(a: NamedAnonymousMixed, ...args: NamedAnonymousMixed[3]) {} + +type ToAnonymousTuple = { + [K in keyof T]: [K, T[K], keyof T, T]; +}; + +type AnonymousToAnonymous = ToAnonymousTuple<[boolean, number]>; +type MixedToAnonymous = ToAnonymousTuple<[boolean, second: number]>; +type NamedToAnonymous = ToAnonymousTuple<[first: boolean, second: number]>; + +type ToMixedTuple = { + [K in keyof T]: [K, second: T[K], keyof T, fourth: T]; +}; + +type AnonymousToMixed = ToMixedTuple<[boolean, number]>; +type MixedToMixed = ToMixedTuple<[boolean, second: number]>; +type NamedToMixed = ToMixedTuple<[first: boolean, second: number]>; + +type MixedSpread = [first: boolean, ...[second: string]]; + +type ConditionalTuple = [ + first: boolean, + ...(0 extends 0 ? [second: string] : []) +]; + +type AddMixedConditional = [ + first: boolean, + null, + third: T extends number ? "a" : "b", + ...(T extends 0 ? [fourth: "c"] : []) +]; + +type AddMixedConditionalBoolean = AddMixedConditional; +type AddMixedConditionalLiteral = AddMixedConditional<0>; +type AddMixedConditionalNumberPrimitive = AddMixedConditional; + +declare function test( + arg: [ + ...{ + [K in keyof T]: { + type: T[K]; + }; + } + ] +): T; + +declare const input: [first: { type: number }, { type: string }]; + +const output = test(input);