Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 11b9118

Browse filesBrowse files
committed
Merge pull request #428 from Microsoft/tupleTypes
Adding support for tuple types (e.g. [number, string])
2 parents b9ebb36 + b4cddc3 commit 11b9118
Copy full SHA for 11b9118

9 files changed

+324-43Lines changed: 324 additions & 43 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+125-28Lines changed: 125 additions & 28 deletions
Large diffs are not rendered by default.
Collapse file

‎src/compiler/core.ts‎

Copy file name to clipboardExpand all lines: src/compiler/core.ts
+16-10Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ module ts {
1919

2020
export function contains<T>(array: T[], value: T): boolean {
2121
if (array) {
22-
var len = array.length;
23-
for (var i = 0; i < len; i++) {
22+
for (var i = 0, len = array.length; i < len; i++) {
2423
if (array[i] === value) {
2524
return true;
2625
}
@@ -31,8 +30,7 @@ module ts {
3130

3231
export function indexOf<T>(array: T[], value: T): number {
3332
if (array) {
34-
var len = array.length;
35-
for (var i = 0; i < len; i++) {
33+
for (var i = 0, len = array.length; i < len; i++) {
3634
if (array[i] === value) {
3735
return i;
3836
}
@@ -42,9 +40,8 @@ module ts {
4240
}
4341

4442
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
45-
var result: T[];
4643
if (array) {
47-
result = [];
44+
var result: T[] = [];
4845
for (var i = 0, len = array.length; i < len; i++) {
4946
var item = array[i];
5047
if (f(item)) {
@@ -56,11 +53,9 @@ module ts {
5653
}
5754

5855
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
59-
var result: U[];
6056
if (array) {
61-
result = [];
62-
var len = array.length;
63-
for (var i = 0; i < len; i++) {
57+
var result: U[] = [];
58+
for (var i = 0, len = array.length; i < len; i++) {
6459
result.push(f(array[i]));
6560
}
6661
}
@@ -73,6 +68,17 @@ module ts {
7368
return array1.concat(array2);
7469
}
7570

71+
export function uniqueElements<T>(array: T[]): T[] {
72+
if (array) {
73+
var result: T[] = [];
74+
for (var i = 0, len = array.length; i < len; i++) {
75+
var item = array[i];
76+
if (!contains(result, item)) result.push(item);
77+
}
78+
}
79+
return result;
80+
}
81+
7682
export function sum(array: any[], prop: string): number {
7783
var result = 0;
7884
for (var i = 0; i < array.length; i++) {
Collapse file

‎src/compiler/diagnosticInformationMap.generated.ts‎

Copy file name to clipboardExpand all lines: src/compiler/diagnosticInformationMap.generated.ts
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ module ts {
8484
An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." },
8585
An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." },
8686
Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." },
87+
A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." },
8788
Variable_declaration_list_cannot_be_empty: { code: 1123, category: DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." },
8889
Digit_expected: { code: 1124, category: DiagnosticCategory.Error, key: "Digit expected." },
8990
Hexadecimal_digit_expected: { code: 1125, category: DiagnosticCategory.Error, key: "Hexadecimal digit expected." },
Collapse file

‎src/compiler/diagnosticMessages.json‎

Copy file name to clipboardExpand all lines: src/compiler/diagnosticMessages.json
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,10 @@
327327
"category": "Error",
328328
"code": 1121
329329
},
330+
"A tuple type element list cannot be empty.": {
331+
"category": "Error",
332+
"code": 1122
333+
},
330334
"Variable declaration list cannot be empty.": {
331335
"category": "Error",
332336
"code": 1123
Collapse file

‎src/compiler/parser.ts‎

Copy file name to clipboardExpand all lines: src/compiler/parser.ts
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,8 @@ module ts {
228228
return children((<TypeLiteralNode>node).members);
229229
case SyntaxKind.ArrayType:
230230
return child((<ArrayTypeNode>node).elementType);
231+
case SyntaxKind.TupleType:
232+
return children((<TupleTypeNode>node).elementTypes);
231233
case SyntaxKind.ArrayLiteral:
232234
return children((<ArrayLiteral>node).elements);
233235
case SyntaxKind.ObjectLiteral:
@@ -520,6 +522,7 @@ module ts {
520522
Parameters, // Parameters in parameter list
521523
TypeParameters, // Type parameters in type parameter list
522524
TypeArguments, // Type arguments in type argument list
525+
TupleElementTypes, // Element types in tuple element type list
523526
Count // Number of parsing contexts
524527
}
525528

@@ -547,6 +550,7 @@ module ts {
547550
case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected;
548551
case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected;
549552
case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected;
553+
case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected;
550554
}
551555
};
552556

@@ -1015,6 +1019,7 @@ module ts {
10151019
case ParsingContext.Parameters:
10161020
return isParameter();
10171021
case ParsingContext.TypeArguments:
1022+
case ParsingContext.TupleElementTypes:
10181023
return isType();
10191024
}
10201025

@@ -1050,6 +1055,7 @@ module ts {
10501055
// Tokens other than ')' are here for better error recovery
10511056
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken;
10521057
case ParsingContext.ArrayLiteralMembers:
1058+
case ParsingContext.TupleElementTypes:
10531059
return token === SyntaxKind.CloseBracketToken;
10541060
case ParsingContext.Parameters:
10551061
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
@@ -1570,6 +1576,17 @@ module ts {
15701576
return finishNode(node);
15711577
}
15721578

1579+
function parseTupleType(): TupleTypeNode {
1580+
var node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
1581+
var startTokenPos = scanner.getTokenPos();
1582+
var startErrorCount = file.syntacticErrors.length;
1583+
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
1584+
if (!node.elementTypes.length && file.syntacticErrors.length === startErrorCount) {
1585+
grammarErrorAtPos(startTokenPos, scanner.getStartPos() - startTokenPos, Diagnostics.A_tuple_type_element_list_cannot_be_empty);
1586+
}
1587+
return finishNode(node);
1588+
}
1589+
15731590
function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode {
15741591
var node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
15751592
var member = <SignatureDeclaration>createNode(signatureKind);
@@ -1600,6 +1617,8 @@ module ts {
16001617
return parseTypeQuery();
16011618
case SyntaxKind.OpenBraceToken:
16021619
return parseTypeLiteral();
1620+
case SyntaxKind.OpenBracketToken:
1621+
return parseTupleType();
16031622
case SyntaxKind.OpenParenToken:
16041623
case SyntaxKind.LessThanToken:
16051624
return parseFunctionType(SyntaxKind.CallSignature);
@@ -1623,6 +1642,7 @@ module ts {
16231642
case SyntaxKind.VoidKeyword:
16241643
case SyntaxKind.TypeOfKeyword:
16251644
case SyntaxKind.OpenBraceToken:
1645+
case SyntaxKind.OpenBracketToken:
16261646
case SyntaxKind.LessThanToken:
16271647
case SyntaxKind.NewKeyword:
16281648
return true;
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+15-4Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ module ts {
149149
TypeQuery,
150150
TypeLiteral,
151151
ArrayType,
152+
TupleType,
152153
// Expression
153154
ArrayLiteral,
154155
ObjectLiteral,
@@ -219,7 +220,7 @@ module ts {
219220
FirstFutureReservedWord = ImplementsKeyword,
220221
LastFutureReservedWord = YieldKeyword,
221222
FirstTypeNode = TypeReference,
222-
LastTypeNode = ArrayType,
223+
LastTypeNode = TupleType,
223224
FirstPunctuation = OpenBraceToken,
224225
LastPunctuation = CaretEqualsToken
225226
}
@@ -320,6 +321,10 @@ module ts {
320321
elementType: TypeNode;
321322
}
322323

324+
export interface TupleTypeNode extends TypeNode {
325+
elementTypes: NodeArray<TypeNode>;
326+
}
327+
323328
export interface StringLiteralTypeNode extends TypeNode {
324329
text: string;
325330
}
@@ -803,13 +808,14 @@ module ts {
803808
Class = 0x00000400, // Class
804809
Interface = 0x00000800, // Interface
805810
Reference = 0x00001000, // Generic type reference
806-
Anonymous = 0x00002000, // Anonymous
807-
FromSignature = 0x00004000, // Created for signature assignment check
811+
Tuple = 0x00002000, // Tuple
812+
Anonymous = 0x00004000, // Anonymous
813+
FromSignature = 0x00008000, // Created for signature assignment check
808814

809815
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
810816
StringLike = String | StringLiteral,
811817
NumberLike = Number | Enum,
812-
ObjectType = Class | Interface | Reference | Anonymous
818+
ObjectType = Class | Interface | Reference | Tuple | Anonymous
813819
}
814820

815821
// Properties common to all types
@@ -862,6 +868,11 @@ module ts {
862868
openReferenceChecks: Map<boolean>; // Open type reference check cache
863869
}
864870

871+
export interface TupleType extends ObjectType {
872+
elementTypes: Type[]; // Element types
873+
baseArrayType: TypeReference; // Array<T> where T is best common type of element types
874+
}
875+
865876
// Resolved object type
866877
export interface ResolvedObjectType extends ObjectType {
867878
members: SymbolTable; // Properties by name
Collapse file
+87Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
==== tests/cases/compiler/tupleTypes.ts (9 errors) ====
2+
var v1: []; // Error
3+
~~
4+
!!! A tuple type element list cannot be empty.
5+
var v2: [number];
6+
var v3: [number, string];
7+
var v4: [number, [string, string]];
8+
9+
var t: [number, string];
10+
var t0 = t[0]; // number
11+
var t0: number;
12+
var t1 = t[1]; // string
13+
var t1: string;
14+
var t2 = t[2]; // {}
15+
var t2: {};
16+
17+
t = []; // Error
18+
~
19+
!!! Type '{}[]' is not assignable to type '[number, string]':
20+
!!! Property '0' is missing in type '{}[]'.
21+
t = [1]; // Error
22+
~
23+
!!! Type '[number]' is not assignable to type '[number, string]':
24+
!!! Property '1' is missing in type '[number]'.
25+
t = [1, "hello"]; // Ok
26+
t = ["hello", 1]; // Error
27+
~
28+
!!! Type '[string, number]' is not assignable to type '[number, string]':
29+
!!! Types of property '0' are incompatible:
30+
!!! Type 'string' is not assignable to type 'number'.
31+
t = [1, "hello", 2]; // Ok
32+
33+
var tf: [string, (x: string) => number] = ["hello", x => x.length];
34+
35+
declare function ff<T, U>(a: T, b: [T, (x: T) => U]): U;
36+
var ff1 = ff("hello", ["foo", x => x.length]);
37+
var ff1: number;
38+
39+
function tuple2<T0, T1>(item0: T0, item1: T1): [T0, T1]{
40+
return [item0, item1];
41+
}
42+
43+
var tt = tuple2(1, "string");
44+
var tt0 = tt[0];
45+
var tt0: number;
46+
var tt1 = tt[1];
47+
var tt1: string;
48+
var tt2 = tt[2];
49+
var tt2: {};
50+
51+
tt = tuple2(1, undefined);
52+
tt = [1, undefined];
53+
tt = [undefined, undefined];
54+
tt = []; // Error
55+
~~
56+
!!! Type '{}[]' is not assignable to type '[number, string]'.
57+
58+
var a: number[];
59+
var a1: [number, string];
60+
var a2: [number, number];
61+
var a3: [number, {}];
62+
a = a1; // Error
63+
~
64+
!!! Type '[number, string]' is not assignable to type 'number[]':
65+
!!! Types of property 'pop' are incompatible:
66+
!!! Type '() => {}' is not assignable to type '() => number':
67+
!!! Type '{}' is not assignable to type 'number'.
68+
a = a2;
69+
a = a3; // Error
70+
~
71+
!!! Type '[number, {}]' is not assignable to type 'number[]':
72+
!!! Types of property 'pop' are incompatible:
73+
!!! Type '() => {}' is not assignable to type '() => number':
74+
!!! Type '{}' is not assignable to type 'number'.
75+
a1 = a2; // Error
76+
~~
77+
!!! Type '[number, number]' is not assignable to type '[number, string]':
78+
!!! Types of property '1' are incompatible:
79+
!!! Type 'number' is not assignable to type 'string'.
80+
a1 = a3; // Error
81+
~~
82+
!!! Type '[number, {}]' is not assignable to type '[number, string]':
83+
!!! Types of property '1' are incompatible:
84+
!!! Type '{}' is not assignable to type 'string'.
85+
a3 = a1;
86+
a3 = a2;
87+
Collapse file

‎tests/baselines/reference/typeName1.errors.txt‎

Copy file name to clipboardExpand all lines: tests/baselines/reference/typeName1.errors.txt
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
==== tests/cases/compiler/typeName1.ts (16 errors) ====
1+
==== tests/cases/compiler/typeName1.ts (17 errors) ====
22
interface I {
33
k;
44
}
@@ -55,6 +55,8 @@
5555
~~~
5656
!!! Type 'number' is not assignable to type '{ z: I; x: boolean; y: (s: string) => boolean; w: { (): boolean; [x: string]: { x: any; y: any; }; [x: number]: { x: any; y: any; }; z: I; }; }[][]':
5757
!!! Property 'length' is missing in type 'Number'.
58+
~~~~
59+
!!! Property 'z' of type 'I' is not assignable to string index type '{ x: any; y: any; }'.
5860
var x13:{ new(): number; new(n:number):number; x: string; w: {y: number;}; (): {}; } = 3;
5961
~~~
6062
!!! Type 'number' is not assignable to type '{ (): {}; new (): number; new (n: number): number; x: string; w: { y: number; }; }':
Collapse file

‎tests/cases/compiler/tupleTypes.ts‎

Copy file name to clipboard
+53Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
var v1: []; // Error
2+
var v2: [number];
3+
var v3: [number, string];
4+
var v4: [number, [string, string]];
5+
6+
var t: [number, string];
7+
var t0 = t[0]; // number
8+
var t0: number;
9+
var t1 = t[1]; // string
10+
var t1: string;
11+
var t2 = t[2]; // {}
12+
var t2: {};
13+
14+
t = []; // Error
15+
t = [1]; // Error
16+
t = [1, "hello"]; // Ok
17+
t = ["hello", 1]; // Error
18+
t = [1, "hello", 2]; // Ok
19+
20+
var tf: [string, (x: string) => number] = ["hello", x => x.length];
21+
22+
declare function ff<T, U>(a: T, b: [T, (x: T) => U]): U;
23+
var ff1 = ff("hello", ["foo", x => x.length]);
24+
var ff1: number;
25+
26+
function tuple2<T0, T1>(item0: T0, item1: T1): [T0, T1]{
27+
return [item0, item1];
28+
}
29+
30+
var tt = tuple2(1, "string");
31+
var tt0 = tt[0];
32+
var tt0: number;
33+
var tt1 = tt[1];
34+
var tt1: string;
35+
var tt2 = tt[2];
36+
var tt2: {};
37+
38+
tt = tuple2(1, undefined);
39+
tt = [1, undefined];
40+
tt = [undefined, undefined];
41+
tt = []; // Error
42+
43+
var a: number[];
44+
var a1: [number, string];
45+
var a2: [number, number];
46+
var a3: [number, {}];
47+
a = a1; // Error
48+
a = a2;
49+
a = a3; // Error
50+
a1 = a2; // Error
51+
a1 = a3; // Error
52+
a3 = a1;
53+
a3 = a2;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.