Skip to content

Commit c80c84a

Browse files
committed
Initial draft of named tuple members
1 parent 167f954 commit c80c84a

File tree

49 files changed

+901
-436
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+901
-436
lines changed

src/compiler/checker.ts

+82-26
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

+12
Original file line numberDiff line numberDiff line change
@@ -3513,6 +3513,18 @@
35133513
"category": "Error",
35143514
"code": 5083
35153515
},
3516+
"Tuple members must all have names or not have names.": {
3517+
"category": "Error",
3518+
"code": 5084
3519+
},
3520+
"Tuple members express optionality with a trailing question mark on the type, a question mark on the member name is invalid.": {
3521+
"category": "Error",
3522+
"code": 5085
3523+
},
3524+
"Rest tuple members are declared with a `...` on the type. A `...` on the name is invalid.": {
3525+
"category": "Error",
3526+
"code": 5086
3527+
},
35163528

35173529
"Generates a sourcemap for each corresponding '.d.ts' file.": {
35183530
"category": "Message",

src/compiler/emitter.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,8 @@ namespace ts {
13701370
case SyntaxKind.RestType:
13711371
case SyntaxKind.JSDocVariadicType:
13721372
return emitRestOrJSDocVariadicType(node as RestTypeNode | JSDocVariadicType);
1373+
case SyntaxKind.NamedTupleMember:
1374+
return emitNamedTupleMember(node as NamedTupleMember);
13731375

13741376
// Binding patterns
13751377
case SyntaxKind.ObjectBindingPattern:
@@ -2099,9 +2101,17 @@ namespace ts {
20992101
}
21002102

21012103
function emitTupleType(node: TupleTypeNode) {
2102-
writePunctuation("[");
2103-
emitList(node, node.elementTypes, ListFormat.TupleTypeElements);
2104-
writePunctuation("]");
2104+
emitTokenWithComment(SyntaxKind.OpenBracketToken, node.pos, writePunctuation, node);
2105+
const flags = getEmitFlags(node) & EmitFlags.SingleLine ? ListFormat.SingleLineTupleTypeElements : ListFormat.MultiLineTupleTypeElements;
2106+
emitList(node, node.elements, flags | ListFormat.NoSpaceIfEmpty);
2107+
emitTokenWithComment(SyntaxKind.CloseBracketToken, node.elements.end, writePunctuation, node);
2108+
}
2109+
2110+
function emitNamedTupleMember(node: NamedTupleMember) {
2111+
emit(node.name);
2112+
emitTokenWithComment(SyntaxKind.ColonToken, node.name.end, writePunctuation, node);
2113+
writeSpace();
2114+
emit(node.type);
21052115
}
21062116

21072117
function emitOptionalType(node: OptionalTypeNode) {

src/compiler/factoryPublic.ts

+34-5
Original file line numberDiff line numberDiff line change
@@ -810,15 +810,15 @@ namespace ts {
810810
: node;
811811
}
812812

813-
export function createTupleTypeNode(elementTypes: readonly TypeNode[]) {
813+
export function createTupleTypeNode(elements: readonly (TypeNode | NamedTupleMember)[]) {
814814
const node = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode;
815-
node.elementTypes = createNodeArray(elementTypes);
815+
node.elements = createNodeArray(elements);
816816
return node;
817817
}
818818

819-
export function updateTupleTypeNode(node: TupleTypeNode, elementTypes: readonly TypeNode[]) {
820-
return node.elementTypes !== elementTypes
821-
? updateNode(createTupleTypeNode(elementTypes), node)
819+
export function updateTupleTypeNode(node: TupleTypeNode, elements: readonly (TypeNode | NamedTupleMember)[]) {
820+
return node.elements !== elements
821+
? updateNode(createTupleTypeNode(elements), node)
822822
: node;
823823
}
824824

@@ -934,6 +934,20 @@ namespace ts {
934934
: node;
935935
}
936936

937+
export function createNamedTupleMember(name: Identifier, type: TypeNode) {
938+
const node = <NamedTupleMember>createSynthesizedNode(SyntaxKind.NamedTupleMember);
939+
node.name = name;
940+
node.type = type;
941+
return node;
942+
}
943+
944+
export function updateNamedTupleMember(node: NamedTupleMember, name: Identifier, type: TypeNode) {
945+
return node.name !== name
946+
|| node.type !== type
947+
? updateNode(createNamedTupleMember(name, type), node)
948+
: node;
949+
}
950+
937951
export function createThisTypeNode() {
938952
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
939953
}
@@ -2524,6 +2538,21 @@ namespace ts {
25242538
return node;
25252539
}
25262540

2541+
2542+
/* @internal */
2543+
export function createJSDocVariadicType(type: TypeNode): JSDocVariadicType {
2544+
const node = createSynthesizedNode(SyntaxKind.JSDocVariadicType) as JSDocVariadicType;
2545+
node.type = type;
2546+
return node;
2547+
}
2548+
2549+
/* @internal */
2550+
export function updateJSDocVariadicType(node: JSDocVariadicType, type: TypeNode): JSDocVariadicType {
2551+
return node.type !== type
2552+
? updateNode(createJSDocVariadicType(type), node)
2553+
: node;
2554+
}
2555+
25272556
// JSX
25282557

25292558
export function createJsxElement(openingElement: JsxOpeningElement, children: readonly JsxChild[], closingElement: JsxClosingElement) {

src/compiler/parser.ts

+31-2
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ namespace ts {
179179
case SyntaxKind.ArrayType:
180180
return visitNode(cbNode, (<ArrayTypeNode>node).elementType);
181181
case SyntaxKind.TupleType:
182-
return visitNodes(cbNode, cbNodes, (<TupleTypeNode>node).elementTypes);
182+
return visitNodes(cbNode, cbNodes, (<TupleTypeNode>node).elements);
183183
case SyntaxKind.UnionType:
184184
case SyntaxKind.IntersectionType:
185185
return visitNodes(cbNode, cbNodes, (<UnionOrIntersectionTypeNode>node).types);
@@ -207,6 +207,11 @@ namespace ts {
207207
visitNode(cbNode, (<MappedTypeNode>node).type);
208208
case SyntaxKind.LiteralType:
209209
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
210+
case SyntaxKind.NamedTupleMember:
211+
return visitNode(cbNode, (<NamedTupleMember>node).dotDotDotToken) ||
212+
visitNode(cbNode, (<NamedTupleMember>node).name) ||
213+
visitNode(cbNode, (<NamedTupleMember>node).questionToken) ||
214+
visitNode(cbNode, (<NamedTupleMember>node).type);
210215
case SyntaxKind.ObjectBindingPattern:
211216
case SyntaxKind.ArrayBindingPattern:
212217
return visitNodes(cbNode, cbNodes, (<BindingPattern>node).elements);
@@ -3056,9 +3061,33 @@ namespace ts {
30563061
return type;
30573062
}
30583063

3064+
function isNextTokenColonOrQuestionColon() {
3065+
return nextToken() === SyntaxKind.ColonToken || (token() === SyntaxKind.QuestionToken && nextToken() === SyntaxKind.ColonToken);
3066+
}
3067+
3068+
function isTupleElementName() {
3069+
if (token() === SyntaxKind.DotDotDotToken) {
3070+
return tokenIsIdentifierOrKeyword(nextToken()) && isNextTokenColonOrQuestionColon();
3071+
}
3072+
return tokenIsIdentifierOrKeyword(token()) && isNextTokenColonOrQuestionColon();
3073+
}
3074+
3075+
function parseTupleElementNameOrTupleElementType() {
3076+
if (lookAhead(isTupleElementName)) {
3077+
const node = <NamedTupleMember>createNode(SyntaxKind.NamedTupleMember);
3078+
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
3079+
node.name = parseIdentifierName();
3080+
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
3081+
parseExpected(SyntaxKind.ColonToken);
3082+
node.type = parseTupleElementType();
3083+
return addJSDocComment(finishNode(node));
3084+
}
3085+
return parseTupleElementType();
3086+
}
3087+
30593088
function parseTupleType(): TupleTypeNode {
30603089
const node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
3061-
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
3090+
node.elements = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElementNameOrTupleElementType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
30623091
return finishNode(node);
30633092
}
30643093

src/compiler/transformers/declarations.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,10 @@ namespace ts {
10181018
}
10191019
}
10201020

1021+
if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) {
1022+
setEmitFlags(input, EmitFlags.SingleLine);
1023+
}
1024+
10211025
return cleanup(visitEachChild(input, visitDeclarationSubtree, context));
10221026

10231027
function cleanup<T extends Node>(returnValue: T | undefined): T | undefined {

src/compiler/types.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ namespace ts {
328328
IndexedAccessType,
329329
MappedType,
330330
LiteralType,
331+
NamedTupleMember,
331332
ImportType,
332333
// Binding patterns
333334
ObjectBindingPattern,
@@ -699,6 +700,7 @@ namespace ts {
699700
| ConstructorTypeNode
700701
| JSDocFunctionType
701702
| ExportDeclaration
703+
| NamedTupleMember
702704
| EndOfFileToken;
703705

704706
export type HasType =
@@ -1273,7 +1275,15 @@ namespace ts {
12731275

12741276
export interface TupleTypeNode extends TypeNode {
12751277
kind: SyntaxKind.TupleType;
1276-
elementTypes: NodeArray<TypeNode>;
1278+
elements: NodeArray<TypeNode | NamedTupleMember>;
1279+
}
1280+
1281+
export interface NamedTupleMember extends TypeNode, JSDocContainer {
1282+
kind: SyntaxKind.NamedTupleMember;
1283+
dotDotDotToken?: Token<SyntaxKind.DotDotDotToken>;
1284+
name: Identifier;
1285+
questionToken?: Token<SyntaxKind.QuestionToken>;
1286+
type: TypeNode;
12771287
}
12781288

12791289
export interface OptionalTypeNode extends TypeNode {
@@ -6570,7 +6580,8 @@ namespace ts {
65706580
SingleLineTypeLiteralMembers = SingleLine | SpaceBetweenBraces | SpaceBetweenSiblings,
65716581
MultiLineTypeLiteralMembers = MultiLine | Indented | OptionalIfEmpty,
65726582

6573-
TupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
6583+
SingleLineTupleTypeElements = CommaDelimited | SpaceBetweenSiblings | SingleLine,
6584+
MultiLineTupleTypeElements = CommaDelimited | Indented | SpaceBetweenSiblings | MultiLine,
65746585
UnionTypeConstituents = BarDelimited | SpaceBetweenSiblings | SingleLine,
65756586
IntersectionTypeConstituents = AmpersandDelimited | SpaceBetweenSiblings | SingleLine,
65766587
ObjectBindingPatternElements = SingleLine | AllowTrailingComma | SpaceBetweenBraces | CommaDelimited | SpaceBetweenSiblings | NoSpaceIfEmpty,

src/compiler/utilities.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -2702,7 +2702,10 @@ namespace ts {
27022702
}
27032703

27042704
export function walkUpParenthesizedTypes(node: Node) {
2705-
return walkUp(node, SyntaxKind.ParenthesizedType);
2705+
while (node && (node.kind === SyntaxKind.ParenthesizedType || node.kind === SyntaxKind.NamedTupleMember)) {
2706+
node = node.parent;
2707+
}
2708+
return node;
27062709
}
27072710

27082711
export function walkUpParenthesizedExpressions(node: Node) {

src/compiler/visitorPublic.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ namespace ts {
480480

481481
case SyntaxKind.TupleType:
482482
return updateTupleTypeNode((<TupleTypeNode>node),
483-
nodesVisitor((<TupleTypeNode>node).elementTypes, visitor, isTypeNode));
483+
nodesVisitor((<TupleTypeNode>node).elements, visitor, isTypeNode));
484484

485485
case SyntaxKind.OptionalType:
486486
return updateOptionalTypeNode((<OptionalTypeNode>node),
@@ -517,6 +517,12 @@ namespace ts {
517517
(<ImportTypeNode>node).isTypeOf
518518
);
519519

520+
case SyntaxKind.NamedTupleMember:
521+
return updateNamedTupleMember(<NamedTupleMember>node,
522+
visitNode((<NamedTupleMember>node).name, visitor, isIdentifierName),
523+
visitNode((<NamedTupleMember>node).type, visitor, isTypeNode),
524+
);
525+
520526
case SyntaxKind.ParenthesizedType:
521527
return updateParenthesizedType(<ParenthesizedTypeNode>node,
522528
visitNode((<ParenthesizedTypeNode>node).type, visitor, isTypeNode));

src/services/refactors/extractType.ts

+5
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ namespace ts.refactor {
145145
}
146146
}
147147
}
148+
149+
if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) {
150+
setEmitFlags(node, EmitFlags.SingleLine);
151+
}
152+
148153
return forEachChild(node, visitor);
149154
}
150155
}

src/testRunner/unittests/printer.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ namespace ts {
229229
// https://github.com/Microsoft/TypeScript/issues/15651
230230
printsCorrectly("functionTypes", {}, printer => printer.printNode(
231231
EmitHint.Unspecified,
232-
createTupleTypeNode([
232+
setEmitFlags(createTupleTypeNode([
233233
createFunctionTypeNode(
234234
/*typeArguments*/ undefined,
235235
[createParameter(
@@ -293,7 +293,7 @@ namespace ts {
293293
)],
294294
createKeywordTypeNode(SyntaxKind.AnyKeyword)
295295
),
296-
]),
296+
]), EmitFlags.SingleLine),
297297
createSourceFile("source.ts", "", ScriptTarget.ES2015)
298298
));
299299
});

tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType0.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"flags": "JSDoc",
66
"modifierFlagsCache": 0,
77
"transformFlags": 0,
8-
"elementTypes": {
8+
"elements": {
99
"length": 0,
1010
"pos": 2,
1111
"end": 2

tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType1.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"flags": "JSDoc",
66
"modifierFlagsCache": 0,
77
"transformFlags": 0,
8-
"elementTypes": {
8+
"elements": {
99
"0": {
1010
"kind": "NumberKeyword",
1111
"pos": 2,

tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType2.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"flags": "JSDoc",
66
"modifierFlagsCache": 0,
77
"transformFlags": 0,
8-
"elementTypes": {
8+
"elements": {
99
"0": {
1010
"kind": "NumberKeyword",
1111
"pos": 2,

tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleType3.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"flags": "JSDoc",
66
"modifierFlagsCache": 0,
77
"transformFlags": 0,
8-
"elementTypes": {
8+
"elements": {
99
"0": {
1010
"kind": "NumberKeyword",
1111
"pos": 2,

tests/baselines/reference/JSDocParsing/TypeExpressions.parsesCorrectly.tupleTypeWithTrailingComma.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"flags": "JSDoc",
66
"modifierFlagsCache": 0,
77
"transformFlags": 0,
8-
"elementTypes": {
8+
"elements": {
99
"0": {
1010
"kind": "NumberKeyword",
1111
"pos": 2,

0 commit comments

Comments
 (0)