Tuples are a sort of list but with a limited set of items. In JavaScript,
tuples are created using arrays.
In Flow you can create tuples using the [type, type, type]
syntax.
1
2
3
|
let tuple1: [number] = [1];
let tuple2: [number, boolean] = [1, true];
let tuple3: [number, boolean, string] = [1, true, "three"];
|
{"value":"let tuple1: [number] = [1];\nlet tuple2: [number, boolean] = [1, true];\nlet tuple3: [number, boolean, string] = [1, true, \"three\"];\n","tokens":[{"type":"T_LET","context":"normal","value":"let","line":1,"start":0,"end":3},{"type":"T_IDENTIFIER","context":"normal","value":"tuple1","line":1,"start":4,"end":10},{"type":"T_COLON","context":"type","value":":","line":1,"start":10,"end":11},{"type":"T_LBRACKET","context":"type","value":"[","line":1,"start":12,"end":13},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":1,"start":13,"end":19},{"type":"T_RBRACKET","context":"type","value":"]","line":1,"start":19,"end":20},{"type":"T_ASSIGN","context":"normal","value":"=","line":1,"start":21,"end":22},{"type":"T_LBRACKET","context":"normal","value":"[","line":1,"start":23,"end":24},{"type":"T_NUMBER","context":"normal","value":"1","line":1,"start":24,"end":25},{"type":"T_RBRACKET","context":"normal","value":"]","line":1,"start":25,"end":26},{"type":"T_SEMICOLON","context":"normal","value":";","line":1,"start":26,"end":27},{"type":"T_LET","context":"normal","value":"let","line":2,"start":28,"end":31},{"type":"T_IDENTIFIER","context":"normal","value":"tuple2","line":2,"start":32,"end":38},{"type":"T_COLON","context":"type","value":":","line":2,"start":38,"end":39},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":40,"end":41},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":41,"end":47},{"type":"T_COMMA","context":"type","value":",","line":2,"start":47,"end":48},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":49,"end":56},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":56,"end":57},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":58,"end":59},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":60,"end":61},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":61,"end":62},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":62,"end":63},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":64,"end":68},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":68,"end":69},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":69,"end":70},{"type":"T_LET","context":"normal","value":"let","line":3,"start":71,"end":74},{"type":"T_IDENTIFIER","context":"normal","value":"tuple3","line":3,"start":75,"end":81},{"type":"T_COLON","context":"type","value":":","line":3,"start":81,"end":82},{"type":"T_LBRACKET","context":"type","value":"[","line":3,"start":83,"end":84},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":3,"start":84,"end":90},{"type":"T_COMMA","context":"type","value":",","line":3,"start":90,"end":91},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":3,"start":92,"end":99},{"type":"T_COMMA","context":"type","value":",","line":3,"start":99,"end":100},{"type":"T_STRING_TYPE","context":"type","value":"string","line":3,"start":101,"end":107},{"type":"T_RBRACKET","context":"type","value":"]","line":3,"start":107,"end":108},{"type":"T_ASSIGN","context":"normal","value":"=","line":3,"start":109,"end":110},{"type":"T_LBRACKET","context":"normal","value":"[","line":3,"start":111,"end":112},{"type":"T_NUMBER","context":"normal","value":"1","line":3,"start":112,"end":113},{"type":"T_COMMA","context":"normal","value":",","line":3,"start":113,"end":114},{"type":"T_TRUE","context":"normal","value":"true","line":3,"start":115,"end":119},{"type":"T_COMMA","context":"normal","value":",","line":3,"start":119,"end":120},{"type":"T_STRING","context":"normal","value":"\"three\"","line":3,"start":121,"end":128},{"type":"T_RBRACKET","context":"normal","value":"]","line":3,"start":128,"end":129},{"type":"T_SEMICOLON","context":"normal","value":";","line":3,"start":129,"end":130}],"errors":[]}
When you are getting a value from a tuple at a specific index, it will return the
type at that index.
1
2
3
4
5
6
|
let tuple: [number, boolean, string] = [1, true, "three"];
let num : number = tuple[0];
let bool : boolean = tuple[1];
let str : string = tuple[2];
|
{"value":"// @flow\nlet tuple: [number, boolean, string] = [1, true, \"three\"];\n\nlet num : number = tuple[0]; // Works!\nlet bool : boolean = tuple[1]; // Works!\nlet str : string = tuple[2]; // Works!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":20,"end":21},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":21,"end":27},{"type":"T_COMMA","context":"type","value":",","line":2,"start":27,"end":28},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":29,"end":36},{"type":"T_COMMA","context":"type","value":",","line":2,"start":36,"end":37},{"type":"T_STRING_TYPE","context":"type","value":"string","line":2,"start":38,"end":44},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":44,"end":45},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":46,"end":47},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":48,"end":49},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":49,"end":50},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":50,"end":51},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":52,"end":56},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":56,"end":57},{"type":"T_STRING","context":"normal","value":"\"three\"","line":2,"start":58,"end":65},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":65,"end":66},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":66,"end":67},{"type":"T_LET","context":"normal","value":"let","line":4,"start":69,"end":72},{"type":"T_IDENTIFIER","context":"normal","value":"num","line":4,"start":73,"end":76},{"type":"T_COLON","context":"type","value":":","line":4,"start":78,"end":79},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":80,"end":86},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":88,"end":89},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":4,"start":90,"end":95},{"type":"T_LBRACKET","context":"normal","value":"[","line":4,"start":95,"end":96},{"type":"T_NUMBER","context":"normal","value":"0","line":4,"start":96,"end":97},{"type":"T_RBRACKET","context":"normal","value":"]","line":4,"start":97,"end":98},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":98,"end":99},{"type":"Line","context":"comment","value":"// Works!","line":4,"start":100,"end":109},{"type":"T_LET","context":"normal","value":"let","line":5,"start":110,"end":113},{"type":"T_IDENTIFIER","context":"normal","value":"bool","line":5,"start":114,"end":118},{"type":"T_COLON","context":"type","value":":","line":5,"start":119,"end":120},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":5,"start":121,"end":128},{"type":"T_ASSIGN","context":"normal","value":"=","line":5,"start":129,"end":130},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":5,"start":131,"end":136},{"type":"T_LBRACKET","context":"normal","value":"[","line":5,"start":136,"end":137},{"type":"T_NUMBER","context":"normal","value":"1","line":5,"start":137,"end":138},{"type":"T_RBRACKET","context":"normal","value":"]","line":5,"start":138,"end":139},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":139,"end":140},{"type":"Line","context":"comment","value":"// Works!","line":5,"start":141,"end":150},{"type":"T_LET","context":"normal","value":"let","line":6,"start":151,"end":154},{"type":"T_IDENTIFIER","context":"normal","value":"str","line":6,"start":155,"end":158},{"type":"T_COLON","context":"type","value":":","line":6,"start":160,"end":161},{"type":"T_STRING_TYPE","context":"type","value":"string","line":6,"start":162,"end":168},{"type":"T_ASSIGN","context":"normal","value":"=","line":6,"start":170,"end":171},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":6,"start":172,"end":177},{"type":"T_LBRACKET","context":"normal","value":"[","line":6,"start":177,"end":178},{"type":"T_NUMBER","context":"normal","value":"2","line":6,"start":178,"end":179},{"type":"T_RBRACKET","context":"normal","value":"]","line":6,"start":179,"end":180},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":180,"end":181},{"type":"Line","context":"comment","value":"// Works!","line":6,"start":182,"end":191}],"errors":[]}
Trying to access an index that does not exist results in an index-out-of-bounds error.
1
2
3
4
|
let tuple: [number, boolean, string] = [1, true, "three"];
let none = tuple[3];
|
Cannot get `tuple[3]` because tuple type [1] only has 3 elements, so index 3 is out of bounds. [invalid-tuple-index]
{"value":"// @flow\nlet tuple: [number, boolean, string] = [1, true, \"three\"];\n\nlet none = tuple[3]; // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":20,"end":21},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":21,"end":27},{"type":"T_COMMA","context":"type","value":",","line":2,"start":27,"end":28},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":29,"end":36},{"type":"T_COMMA","context":"type","value":",","line":2,"start":36,"end":37},{"type":"T_STRING_TYPE","context":"type","value":"string","line":2,"start":38,"end":44},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":44,"end":45},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":46,"end":47},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":48,"end":49},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":49,"end":50},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":50,"end":51},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":52,"end":56},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":56,"end":57},{"type":"T_STRING","context":"normal","value":"\"three\"","line":2,"start":58,"end":65},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":65,"end":66},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":66,"end":67},{"type":"T_LET","context":"normal","value":"let","line":4,"start":69,"end":72},{"type":"T_IDENTIFIER","context":"normal","value":"none","line":4,"start":73,"end":77},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":78,"end":79},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":4,"start":80,"end":85},{"type":"T_LBRACKET","context":"normal","value":"[","line":4,"start":85,"end":86},{"type":"T_NUMBER","context":"normal","value":"3","line":4,"start":86,"end":87},{"type":"T_RBRACKET","context":"normal","value":"]","line":4,"start":87,"end":88},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":88,"end":89},{"type":"Line","context":"comment","value":"// Error!","line":4,"start":90,"end":99}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot get `tuple[3]` because tuple type [1] only has 3 elements, so index 3 is out of bounds. [invalid-tuple-index]","context":"let none = tuple[3]; // Error!","source":"-","start":{"line":4,"column":12,"offset":80},"end":{"line":4,"column":19,"offset":88}}],"operation":null}]}
If Flow doesn’t know which index you are trying to access it will return all
possible types.
1
2
3
4
5
6
7
|
let tuple: [number, boolean, string] = [1, true, "three"];
function getItem(n: number) {
let val: number | boolean | string = tuple[n];
}
|
{"value":"// @flow\nlet tuple: [number, boolean, string] = [1, true, \"three\"];\n\nfunction getItem(n: number) {\n let val: number | boolean | string = tuple[n];\n // ...\n}\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":20,"end":21},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":21,"end":27},{"type":"T_COMMA","context":"type","value":",","line":2,"start":27,"end":28},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":29,"end":36},{"type":"T_COMMA","context":"type","value":",","line":2,"start":36,"end":37},{"type":"T_STRING_TYPE","context":"type","value":"string","line":2,"start":38,"end":44},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":44,"end":45},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":46,"end":47},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":48,"end":49},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":49,"end":50},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":50,"end":51},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":52,"end":56},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":56,"end":57},{"type":"T_STRING","context":"normal","value":"\"three\"","line":2,"start":58,"end":65},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":65,"end":66},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":66,"end":67},{"type":"T_FUNCTION","context":"normal","value":"function","line":4,"start":69,"end":77},{"type":"T_IDENTIFIER","context":"normal","value":"getItem","line":4,"start":78,"end":85},{"type":"T_LPAREN","context":"normal","value":"(","line":4,"start":85,"end":86},{"type":"T_IDENTIFIER","context":"normal","value":"n","line":4,"start":86,"end":87},{"type":"T_COLON","context":"type","value":":","line":4,"start":87,"end":88},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":89,"end":95},{"type":"T_RPAREN","context":"normal","value":")","line":4,"start":95,"end":96},{"type":"T_LCURLY","context":"normal","value":"{","line":4,"start":97,"end":98},{"type":"T_LET","context":"normal","value":"let","line":5,"start":101,"end":104},{"type":"T_IDENTIFIER","context":"normal","value":"val","line":5,"start":105,"end":108},{"type":"T_COLON","context":"type","value":":","line":5,"start":108,"end":109},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":5,"start":110,"end":116},{"type":"T_BIT_OR","context":"type","value":"|","line":5,"start":117,"end":118},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":5,"start":119,"end":126},{"type":"T_BIT_OR","context":"type","value":"|","line":5,"start":127,"end":128},{"type":"T_STRING_TYPE","context":"type","value":"string","line":5,"start":129,"end":135},{"type":"T_ASSIGN","context":"normal","value":"=","line":5,"start":136,"end":137},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":5,"start":138,"end":143},{"type":"T_LBRACKET","context":"normal","value":"[","line":5,"start":143,"end":144},{"type":"T_IDENTIFIER","context":"normal","value":"n","line":5,"start":144,"end":145},{"type":"T_RBRACKET","context":"normal","value":"]","line":5,"start":145,"end":146},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":146,"end":147},{"type":"Line","context":"comment","value":"// ...","line":6,"start":150,"end":156},{"type":"T_RCURLY","context":"normal","value":"}","line":7,"start":157,"end":158}],"errors":[]}
When setting a new value inside a tuple, the new value must match the type at
that index.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
let tuple: [number, boolean, string] = [1, true, "three"];
tuple[0] = 2;
tuple[1] = false;
tuple[2] = "foo";
tuple[0] = "bar";
tuple[1] = 42;
tuple[2] = false;
|
Cannot assign `"bar"` to `tuple[0]` because string [1] is incompatible with number [2]. [incompatible-type]
Cannot assign `42` to `tuple[1]` because number [1] is incompatible with boolean [2]. [incompatible-type]
Cannot assign `false` to `tuple[2]` because boolean [1] is incompatible with string [2]. [incompatible-type]
{"value":"// @flow\nlet tuple: [number, boolean, string] = [1, true, \"three\"];\n\ntuple[0] = 2; // Works!\ntuple[1] = false; // Works!\ntuple[2] = \"foo\"; // Works!\n\n// $ExpectError\ntuple[0] = \"bar\"; // Error!\n// $ExpectError\ntuple[1] = 42; // Error!\n// $ExpectError\ntuple[2] = false; // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":20,"end":21},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":21,"end":27},{"type":"T_COMMA","context":"type","value":",","line":2,"start":27,"end":28},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":29,"end":36},{"type":"T_COMMA","context":"type","value":",","line":2,"start":36,"end":37},{"type":"T_STRING_TYPE","context":"type","value":"string","line":2,"start":38,"end":44},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":44,"end":45},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":46,"end":47},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":48,"end":49},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":49,"end":50},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":50,"end":51},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":52,"end":56},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":56,"end":57},{"type":"T_STRING","context":"normal","value":"\"three\"","line":2,"start":58,"end":65},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":65,"end":66},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":66,"end":67},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":4,"start":69,"end":74},{"type":"T_LBRACKET","context":"normal","value":"[","line":4,"start":74,"end":75},{"type":"T_NUMBER","context":"normal","value":"0","line":4,"start":75,"end":76},{"type":"T_RBRACKET","context":"normal","value":"]","line":4,"start":76,"end":77},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":78,"end":79},{"type":"T_NUMBER","context":"normal","value":"2","line":4,"start":80,"end":81},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":81,"end":82},{"type":"Line","context":"comment","value":"// Works!","line":4,"start":87,"end":96},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":5,"start":97,"end":102},{"type":"T_LBRACKET","context":"normal","value":"[","line":5,"start":102,"end":103},{"type":"T_NUMBER","context":"normal","value":"1","line":5,"start":103,"end":104},{"type":"T_RBRACKET","context":"normal","value":"]","line":5,"start":104,"end":105},{"type":"T_ASSIGN","context":"normal","value":"=","line":5,"start":106,"end":107},{"type":"T_FALSE","context":"normal","value":"false","line":5,"start":108,"end":113},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":113,"end":114},{"type":"Line","context":"comment","value":"// Works!","line":5,"start":115,"end":124},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":6,"start":125,"end":130},{"type":"T_LBRACKET","context":"normal","value":"[","line":6,"start":130,"end":131},{"type":"T_NUMBER","context":"normal","value":"2","line":6,"start":131,"end":132},{"type":"T_RBRACKET","context":"normal","value":"]","line":6,"start":132,"end":133},{"type":"T_ASSIGN","context":"normal","value":"=","line":6,"start":134,"end":135},{"type":"T_STRING","context":"normal","value":"\"foo\"","line":6,"start":136,"end":141},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":141,"end":142},{"type":"Line","context":"comment","value":"// Works!","line":6,"start":143,"end":152},{"type":"Line","context":"comment","value":"// $ExpectError","line":8,"start":154,"end":169},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":9,"start":170,"end":175},{"type":"T_LBRACKET","context":"normal","value":"[","line":9,"start":175,"end":176},{"type":"T_NUMBER","context":"normal","value":"0","line":9,"start":176,"end":177},{"type":"T_RBRACKET","context":"normal","value":"]","line":9,"start":177,"end":178},{"type":"T_ASSIGN","context":"normal","value":"=","line":9,"start":179,"end":180},{"type":"T_STRING","context":"normal","value":"\"bar\"","line":9,"start":181,"end":186},{"type":"T_SEMICOLON","context":"normal","value":";","line":9,"start":186,"end":187},{"type":"Line","context":"comment","value":"// Error!","line":9,"start":188,"end":197},{"type":"Line","context":"comment","value":"// $ExpectError","line":10,"start":198,"end":213},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":11,"start":214,"end":219},{"type":"T_LBRACKET","context":"normal","value":"[","line":11,"start":219,"end":220},{"type":"T_NUMBER","context":"normal","value":"1","line":11,"start":220,"end":221},{"type":"T_RBRACKET","context":"normal","value":"]","line":11,"start":221,"end":222},{"type":"T_ASSIGN","context":"normal","value":"=","line":11,"start":223,"end":224},{"type":"T_NUMBER","context":"normal","value":"42","line":11,"start":225,"end":227},{"type":"T_SEMICOLON","context":"normal","value":";","line":11,"start":227,"end":228},{"type":"Line","context":"comment","value":"// Error!","line":11,"start":232,"end":241},{"type":"Line","context":"comment","value":"// $ExpectError","line":12,"start":242,"end":257},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":13,"start":258,"end":263},{"type":"T_LBRACKET","context":"normal","value":"[","line":13,"start":263,"end":264},{"type":"T_NUMBER","context":"normal","value":"2","line":13,"start":264,"end":265},{"type":"T_RBRACKET","context":"normal","value":"]","line":13,"start":265,"end":266},{"type":"T_ASSIGN","context":"normal","value":"=","line":13,"start":267,"end":268},{"type":"T_FALSE","context":"normal","value":"false","line":13,"start":269,"end":274},{"type":"T_SEMICOLON","context":"normal","value":";","line":13,"start":274,"end":275},{"type":"Line","context":"comment","value":"// Error!","line":13,"start":276,"end":285}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `\"bar\"` to `tuple[0]` because string [1] is incompatible with number [2]. [incompatible-type]","context":"tuple[0] = \"bar\"; // Error!","source":"-","start":{"line":9,"column":12,"offset":181},"end":{"line":9,"column":16,"offset":186}}],"operation":null},{"id":"E2","messages":[{"id":"E2M1","description":"Cannot assign `42` to `tuple[1]` because number [1] is incompatible with boolean [2]. [incompatible-type]","context":"tuple[1] = 42; // Error!","source":"-","start":{"line":11,"column":12,"offset":225},"end":{"line":11,"column":13,"offset":227}}],"operation":null},{"id":"E3","messages":[{"id":"E3M1","description":"Cannot assign `false` to `tuple[2]` because boolean [1] is incompatible with string [2]. [incompatible-type]","context":"tuple[2] = false; // Error!","source":"-","start":{"line":13,"column":12,"offset":269},"end":{"line":13,"column":16,"offset":274}}],"operation":null}]}
Strictly enforced tuple length (arity)
The length of the tuple is known as the “arity”. The length of a tuple is
strictly enforced in Flow.
Tuples only match tuples with same length
This means that a shorter tuple can’t be used in place of a longer one.
1
2
3
4
|
let tuple1: [number, boolean] = [1, true];
let tuple2: [number, boolean, void] = tuple1;
|
Cannot assign `tuple1` to `tuple2` because tuple type [1] has an arity of 2 but tuple type [2] has an arity of 3. [invalid-tuple-arity]
{"value":"// @flow\nlet tuple1: [number, boolean] = [1, true];\n// $ExpectError\nlet tuple2: [number, boolean, void] = tuple1; // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple1","line":2,"start":13,"end":19},{"type":"T_COLON","context":"type","value":":","line":2,"start":19,"end":20},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":21,"end":22},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":22,"end":28},{"type":"T_COMMA","context":"type","value":",","line":2,"start":28,"end":29},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":30,"end":37},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":37,"end":38},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":45,"end":46},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":47,"end":48},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":48,"end":49},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":49,"end":50},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":51,"end":55},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":55,"end":56},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":56,"end":57},{"type":"Line","context":"comment","value":"// $ExpectError","line":3,"start":58,"end":73},{"type":"T_LET","context":"normal","value":"let","line":4,"start":74,"end":77},{"type":"T_IDENTIFIER","context":"normal","value":"tuple2","line":4,"start":78,"end":84},{"type":"T_COLON","context":"type","value":":","line":4,"start":84,"end":85},{"type":"T_LBRACKET","context":"type","value":"[","line":4,"start":86,"end":87},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":87,"end":93},{"type":"T_COMMA","context":"type","value":",","line":4,"start":93,"end":94},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":4,"start":95,"end":102},{"type":"T_COMMA","context":"type","value":",","line":4,"start":102,"end":103},{"type":"T_VOID_TYPE","context":"type","value":"void","line":4,"start":104,"end":108},{"type":"T_RBRACKET","context":"type","value":"]","line":4,"start":108,"end":109},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":110,"end":111},{"type":"T_IDENTIFIER","context":"normal","value":"tuple1","line":4,"start":112,"end":118},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":118,"end":119},{"type":"Line","context":"comment","value":"// Error!","line":4,"start":120,"end":129}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `tuple1` to `tuple2` because tuple type [1] has an arity of 2 but tuple type [2] has an arity of 3. [invalid-tuple-arity]","context":"let tuple2: [number, boolean, void] = tuple1; // Error!","source":"-","start":{"line":4,"column":39,"offset":112},"end":{"line":4,"column":44,"offset":118}}],"operation":null}]}
Also, a longer tuple can’t be used in place of a shorter one.
1
2
3
4
|
let tuple1: [number, boolean, void] = [1, true];
let tuple2: [number, boolean] = tuple1;
|
Cannot assign array literal to `tuple1` because array literal [1] has an arity of 2 but tuple type [2] has an arity of 3. [invalid-tuple-arity]
Cannot assign `tuple1` to `tuple2` because tuple type [1] has an arity of 3 but tuple type [2] has an arity of 2. [invalid-tuple-arity]
{"value":"// @flow\nlet tuple1: [number, boolean, void] = [1, true];\n// $ExpectError\nlet tuple2: [number, boolean] = tuple1; // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple1","line":2,"start":13,"end":19},{"type":"T_COLON","context":"type","value":":","line":2,"start":19,"end":20},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":21,"end":22},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":22,"end":28},{"type":"T_COMMA","context":"type","value":",","line":2,"start":28,"end":29},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":2,"start":30,"end":37},{"type":"T_COMMA","context":"type","value":",","line":2,"start":37,"end":38},{"type":"T_VOID_TYPE","context":"type","value":"void","line":2,"start":39,"end":43},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":43,"end":44},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":45,"end":46},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":47,"end":48},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":48,"end":49},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":49,"end":50},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":51,"end":55},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":55,"end":56},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":56,"end":57},{"type":"Line","context":"comment","value":"// $ExpectError","line":3,"start":58,"end":73},{"type":"T_LET","context":"normal","value":"let","line":4,"start":74,"end":77},{"type":"T_IDENTIFIER","context":"normal","value":"tuple2","line":4,"start":78,"end":84},{"type":"T_COLON","context":"type","value":":","line":4,"start":84,"end":85},{"type":"T_LBRACKET","context":"type","value":"[","line":4,"start":86,"end":87},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":87,"end":93},{"type":"T_COMMA","context":"type","value":",","line":4,"start":93,"end":94},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":4,"start":95,"end":102},{"type":"T_RBRACKET","context":"type","value":"]","line":4,"start":102,"end":103},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":110,"end":111},{"type":"T_IDENTIFIER","context":"normal","value":"tuple1","line":4,"start":112,"end":118},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":118,"end":119},{"type":"Line","context":"comment","value":"// Error!","line":4,"start":120,"end":129}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign array literal to `tuple1` because array literal [1] has an arity of 2 but tuple type [2] has an arity of 3. [invalid-tuple-arity]","context":"let tuple1: [number, boolean, void] = [1, true];","source":"-","start":{"line":2,"column":39,"offset":47},"end":{"line":2,"column":47,"offset":56}}],"operation":null},{"id":"E2","messages":[{"id":"E2M1","description":"Cannot assign `tuple1` to `tuple2` because tuple type [1] has an arity of 3 but tuple type [2] has an arity of 2. [invalid-tuple-arity]","context":"let tuple2: [number, boolean] = tuple1; // Error!","source":"-","start":{"line":4,"column":39,"offset":112},"end":{"line":4,"column":44,"offset":118}}],"operation":null}]}
Tuples don’t match array types
Since Flow does not know the length of an array, an Array<T>
type cannot be
passed into a tuple.
1
2
3
4
|
let array: Array<number> = [1, 2];
let tuple: [number, number] = array;
|
Cannot assign `array` to `tuple` because array type [1] has an unknown number of elements, so is incompatible with tuple type [2]. [invalid-tuple-arity]
{"value":"// @flow\nlet array: Array<number> = [1, 2];\n// $ExpectError\nlet tuple: [number, number] = array; // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"array","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_IDENTIFIER","context":"type","value":"Array","line":2,"start":20,"end":25},{"type":"T_LESS_THAN","context":"type","value":"<","line":2,"start":25,"end":26},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":26,"end":32},{"type":"T_GREATER_THAN","context":"type","value":">","line":2,"start":32,"end":33},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":37,"end":38},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":39,"end":40},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":40,"end":41},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":41,"end":42},{"type":"T_NUMBER","context":"normal","value":"2","line":2,"start":43,"end":44},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":44,"end":45},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":45,"end":46},{"type":"Line","context":"comment","value":"// $ExpectError","line":3,"start":47,"end":62},{"type":"T_LET","context":"normal","value":"let","line":4,"start":63,"end":66},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":4,"start":67,"end":72},{"type":"T_COLON","context":"type","value":":","line":4,"start":72,"end":73},{"type":"T_LBRACKET","context":"type","value":"[","line":4,"start":74,"end":75},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":75,"end":81},{"type":"T_COMMA","context":"type","value":",","line":4,"start":81,"end":82},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":83,"end":89},{"type":"T_RBRACKET","context":"type","value":"]","line":4,"start":89,"end":90},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":91,"end":92},{"type":"T_IDENTIFIER","context":"normal","value":"array","line":4,"start":93,"end":98},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":98,"end":99},{"type":"Line","context":"comment","value":"// Error!","line":4,"start":100,"end":109}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `array` to `tuple` because array type [1] has an unknown number of elements, so is incompatible with tuple type [2]. [invalid-tuple-arity]","context":"let tuple: [number, number] = array; // Error!","source":"-","start":{"line":4,"column":31,"offset":93},"end":{"line":4,"column":35,"offset":98}}],"operation":null}]}
Also a tuple type cannot be passed into to an Array<T>
type, since then you
could mutate the tuple in an unsafe way.
1
2
3
4
|
let tuple: [number, number] = [1, 2];
let array: Array<number> = tuple;
|
Cannot assign `tuple` to `array` because tuple type [1] is incompatible with array type [2]. [incompatible-type]
{"value":"// @flow\nlet tuple: [number, number] = [1, 2];\n// $ExpectError\nlet array: Array<number> = tuple; // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":20,"end":21},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":21,"end":27},{"type":"T_COMMA","context":"type","value":",","line":2,"start":27,"end":28},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":29,"end":35},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":35,"end":36},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":37,"end":38},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":39,"end":40},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":40,"end":41},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":41,"end":42},{"type":"T_NUMBER","context":"normal","value":"2","line":2,"start":43,"end":44},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":44,"end":45},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":45,"end":46},{"type":"Line","context":"comment","value":"// $ExpectError","line":3,"start":47,"end":62},{"type":"T_LET","context":"normal","value":"let","line":4,"start":63,"end":66},{"type":"T_IDENTIFIER","context":"normal","value":"array","line":4,"start":67,"end":72},{"type":"T_COLON","context":"type","value":":","line":4,"start":72,"end":73},{"type":"T_IDENTIFIER","context":"type","value":"Array","line":4,"start":74,"end":79},{"type":"T_LESS_THAN","context":"type","value":"<","line":4,"start":79,"end":80},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":4,"start":80,"end":86},{"type":"T_GREATER_THAN","context":"type","value":">","line":4,"start":86,"end":87},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":91,"end":92},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":4,"start":93,"end":98},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":98,"end":99},{"type":"Line","context":"comment","value":"// Error!","line":4,"start":100,"end":109}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `tuple` to `array` because tuple type [1] is incompatible with array type [2]. [incompatible-type]","context":"let array: Array<number> = tuple; // Error!","source":"-","start":{"line":4,"column":31,"offset":93},"end":{"line":4,"column":35,"offset":98}}],"operation":null}]}
Cannot use mutating array methods on tuples
You cannot use Array.prototype
methods that mutate the tuple, only ones that
do not.
1
2
3
4
5
|
let tuple: [number, number] = [1, 2];
tuple.join(', ');
tuple.push(3);
|
Cannot call `tuple.push` because property `push` is missing in `$ReadOnlyArray` [1]. [prop-missing]
{"value":"// @flow\nlet tuple: [number, number] = [1, 2];\ntuple.join(', '); // Works!\n// $ExpectError\ntuple.push(3); // Error!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_LET","context":"normal","value":"let","line":2,"start":9,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":2,"start":13,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_LBRACKET","context":"type","value":"[","line":2,"start":20,"end":21},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":21,"end":27},{"type":"T_COMMA","context":"type","value":",","line":2,"start":27,"end":28},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":29,"end":35},{"type":"T_RBRACKET","context":"type","value":"]","line":2,"start":35,"end":36},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":37,"end":38},{"type":"T_LBRACKET","context":"normal","value":"[","line":2,"start":39,"end":40},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":40,"end":41},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":41,"end":42},{"type":"T_NUMBER","context":"normal","value":"2","line":2,"start":43,"end":44},{"type":"T_RBRACKET","context":"normal","value":"]","line":2,"start":44,"end":45},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":45,"end":46},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":3,"start":47,"end":52},{"type":"T_PERIOD","context":"normal","value":".","line":3,"start":52,"end":53},{"type":"T_IDENTIFIER","context":"normal","value":"join","line":3,"start":53,"end":57},{"type":"T_LPAREN","context":"normal","value":"(","line":3,"start":57,"end":58},{"type":"T_STRING","context":"normal","value":"', '","line":3,"start":58,"end":62},{"type":"T_RPAREN","context":"normal","value":")","line":3,"start":62,"end":63},{"type":"T_SEMICOLON","context":"normal","value":";","line":3,"start":63,"end":64},{"type":"Line","context":"comment","value":"// Works!","line":3,"start":65,"end":74},{"type":"Line","context":"comment","value":"// $ExpectError","line":4,"start":75,"end":90},{"type":"T_IDENTIFIER","context":"normal","value":"tuple","line":5,"start":91,"end":96},{"type":"T_PERIOD","context":"normal","value":".","line":5,"start":96,"end":97},{"type":"T_IDENTIFIER","context":"normal","value":"push","line":5,"start":97,"end":101},{"type":"T_LPAREN","context":"normal","value":"(","line":5,"start":101,"end":102},{"type":"T_NUMBER","context":"normal","value":"3","line":5,"start":102,"end":103},{"type":"T_RPAREN","context":"normal","value":")","line":5,"start":103,"end":104},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":104,"end":105},{"type":"Line","context":"comment","value":"// Error!","line":5,"start":109,"end":118}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot call `tuple.push` because property `push` is missing in `$ReadOnlyArray` [1]. [prop-missing]","context":"tuple.push(3); // Error!","source":"-","start":{"line":5,"column":7,"offset":97},"end":{"line":5,"column":10,"offset":101}}],"operation":null}]}