JavaScript has a typeof
operator which returns a string describing a value.
1
2
3
|
typeof 1 === 'number'
typeof true === 'boolean'
typeof 'three' === 'string'
|
{"value":"typeof 1 === 'number'\ntypeof true === 'boolean'\ntypeof 'three' === 'string'\n","tokens":[{"type":"T_TYPEOF","context":"normal","value":"typeof","line":1,"start":0,"end":6},{"type":"T_NUMBER","context":"normal","value":"1","line":1,"start":7,"end":8},{"type":"T_STRICT_EQUAL","context":"normal","value":"===","line":1,"start":9,"end":12},{"type":"T_STRING","context":"normal","value":"'number'","line":1,"start":13,"end":21},{"type":"T_TYPEOF","context":"normal","value":"typeof","line":2,"start":22,"end":28},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":29,"end":33},{"type":"T_STRICT_EQUAL","context":"normal","value":"===","line":2,"start":34,"end":37},{"type":"T_STRING","context":"normal","value":"'boolean'","line":2,"start":38,"end":47},{"type":"T_TYPEOF","context":"normal","value":"typeof","line":3,"start":48,"end":54},{"type":"T_STRING","context":"normal","value":"'three'","line":3,"start":55,"end":62},{"type":"T_STRICT_EQUAL","context":"normal","value":"===","line":3,"start":63,"end":66},{"type":"T_STRING","context":"normal","value":"'string'","line":3,"start":67,"end":75}],"errors":[]}
However it is limited in that this string only describes so much about the
type.
1
2
3
|
typeof { foo: true } === 'object'
typeof { bar: true } === 'object'
typeof [true, false] === 'object'
|
{"value":"typeof { foo: true } === 'object'\ntypeof { bar: true } === 'object'\ntypeof [true, false] === 'object'\n","tokens":[{"type":"T_TYPEOF","context":"normal","value":"typeof","line":1,"start":0,"end":6},{"type":"T_LCURLY","context":"normal","value":"{","line":1,"start":7,"end":8},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":1,"start":9,"end":12},{"type":"T_COLON","context":"normal","value":":","line":1,"start":12,"end":13},{"type":"T_TRUE","context":"normal","value":"true","line":1,"start":14,"end":18},{"type":"T_RCURLY","context":"normal","value":"}","line":1,"start":19,"end":20},{"type":"T_STRICT_EQUAL","context":"normal","value":"===","line":1,"start":21,"end":24},{"type":"T_STRING","context":"normal","value":"'object'","line":1,"start":25,"end":33},{"type":"T_TYPEOF","context":"normal","value":"typeof","line":2,"start":34,"end":40},{"type":"T_LCURLY","context":"normal","value":"{","line":2,"start":41,"end":42},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":2,"start":43,"end":46},{"type":"T_COLON","context":"normal","value":":","line":2,"start":46,"end":47},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":48,"end":52},{"type":"T_RCURLY","context":"normal","value":"}","line":2,"start":53,"end":54},{"type":"T_STRICT_EQUAL","context":"normal","value":"===","line":2,"start":55,"end":58},{"type":"T_STRING","context":"normal","value":"'object'","line":2,"start":59,"end":67},{"type":"T_TYPEOF","context":"normal","value":"typeof","line":3,"start":68,"end":74},{"type":"T_LBRACKET","context":"normal","value":"[","line":3,"start":75,"end":76},{"type":"T_TRUE","context":"normal","value":"true","line":3,"start":76,"end":80},{"type":"T_COMMA","context":"normal","value":",","line":3,"start":80,"end":81},{"type":"T_FALSE","context":"normal","value":"false","line":3,"start":82,"end":87},{"type":"T_RBRACKET","context":"normal","value":"]","line":3,"start":87,"end":88},{"type":"T_STRICT_EQUAL","context":"normal","value":"===","line":3,"start":89,"end":92},{"type":"T_STRING","context":"normal","value":"'object'","line":3,"start":93,"end":101}],"errors":[]}
In Flow, there is a similar typeof
operator, but it’s much more powerful.
typeof
type syntax
The typeof
operator returns the Flow type of a given value to be used as a
type.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
let num1 = 42;
let num2: typeof num1 = 3.14;
let num3: typeof num1 = 'world';
let bool1 = true;
let bool2: typeof bool1 = false;
let bool3: typeof bool1 = 42;
let str1 = 'hello';
let str2: typeof str1 = 'world';
let str3: typeof str1 = false;
|
Cannot assign `'world'` to `num3` because string [1] is incompatible with number [2].
Cannot assign `42` to `bool3` because number [1] is incompatible with boolean [2].
Cannot assign `false` to `str3` because boolean [1] is incompatible with string [2].
{"value":"// @flow\nlet num1 = 42;\nlet num2: typeof num1 = 3.14; // Works!\n// $ExpectError\nlet num3: typeof num1 = 'world'; // Error!\n\nlet bool1 = true;\nlet bool2: typeof bool1 = false; // Works!\n// $ExpectError\nlet bool3: typeof bool1 = 42; // Error!\n\nlet str1 = 'hello';\nlet str2: typeof str1 = 'world'; // Works!\n// $ExpectError\nlet str3: typeof str1 = 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":"num1","line":2,"start":13,"end":17},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":18,"end":19},{"type":"T_NUMBER","context":"normal","value":"42","line":2,"start":20,"end":22},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":22,"end":23},{"type":"T_LET","context":"normal","value":"let","line":3,"start":24,"end":27},{"type":"T_IDENTIFIER","context":"normal","value":"num2","line":3,"start":28,"end":32},{"type":"T_COLON","context":"type","value":":","line":3,"start":32,"end":33},{"type":"T_TYPEOF","context":"type","value":"typeof","line":3,"start":34,"end":40},{"type":"T_IDENTIFIER","context":"type","value":"num1","line":3,"start":41,"end":45},{"type":"T_ASSIGN","context":"normal","value":"=","line":3,"start":46,"end":47},{"type":"T_NUMBER","context":"normal","value":"3.14","line":3,"start":48,"end":52},{"type":"T_SEMICOLON","context":"normal","value":";","line":3,"start":52,"end":53},{"type":"Line","context":"comment","value":"// Works!","line":3,"start":58,"end":67},{"type":"Line","context":"comment","value":"// $ExpectError","line":4,"start":68,"end":83},{"type":"T_LET","context":"normal","value":"let","line":5,"start":84,"end":87},{"type":"T_IDENTIFIER","context":"normal","value":"num3","line":5,"start":88,"end":92},{"type":"T_COLON","context":"type","value":":","line":5,"start":92,"end":93},{"type":"T_TYPEOF","context":"type","value":"typeof","line":5,"start":94,"end":100},{"type":"T_IDENTIFIER","context":"type","value":"num1","line":5,"start":101,"end":105},{"type":"T_ASSIGN","context":"normal","value":"=","line":5,"start":106,"end":107},{"type":"T_STRING","context":"normal","value":"'world'","line":5,"start":108,"end":115},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":115,"end":116},{"type":"Line","context":"comment","value":"// Error!","line":5,"start":118,"end":127},{"type":"T_LET","context":"normal","value":"let","line":7,"start":129,"end":132},{"type":"T_IDENTIFIER","context":"normal","value":"bool1","line":7,"start":133,"end":138},{"type":"T_ASSIGN","context":"normal","value":"=","line":7,"start":139,"end":140},{"type":"T_TRUE","context":"normal","value":"true","line":7,"start":141,"end":145},{"type":"T_SEMICOLON","context":"normal","value":";","line":7,"start":145,"end":146},{"type":"T_LET","context":"normal","value":"let","line":8,"start":147,"end":150},{"type":"T_IDENTIFIER","context":"normal","value":"bool2","line":8,"start":151,"end":156},{"type":"T_COLON","context":"type","value":":","line":8,"start":156,"end":157},{"type":"T_TYPEOF","context":"type","value":"typeof","line":8,"start":158,"end":164},{"type":"T_IDENTIFIER","context":"type","value":"bool1","line":8,"start":165,"end":170},{"type":"T_ASSIGN","context":"normal","value":"=","line":8,"start":171,"end":172},{"type":"T_FALSE","context":"normal","value":"false","line":8,"start":173,"end":178},{"type":"T_SEMICOLON","context":"normal","value":";","line":8,"start":178,"end":179},{"type":"Line","context":"comment","value":"// Works!","line":8,"start":181,"end":190},{"type":"Line","context":"comment","value":"// $ExpectError","line":9,"start":191,"end":206},{"type":"T_LET","context":"normal","value":"let","line":10,"start":207,"end":210},{"type":"T_IDENTIFIER","context":"normal","value":"bool3","line":10,"start":211,"end":216},{"type":"T_COLON","context":"type","value":":","line":10,"start":216,"end":217},{"type":"T_TYPEOF","context":"type","value":"typeof","line":10,"start":218,"end":224},{"type":"T_IDENTIFIER","context":"type","value":"bool1","line":10,"start":225,"end":230},{"type":"T_ASSIGN","context":"normal","value":"=","line":10,"start":231,"end":232},{"type":"T_NUMBER","context":"normal","value":"42","line":10,"start":233,"end":235},{"type":"T_SEMICOLON","context":"normal","value":";","line":10,"start":235,"end":236},{"type":"Line","context":"comment","value":"// Error!","line":10,"start":241,"end":250},{"type":"T_LET","context":"normal","value":"let","line":12,"start":252,"end":255},{"type":"T_IDENTIFIER","context":"normal","value":"str1","line":12,"start":256,"end":260},{"type":"T_ASSIGN","context":"normal","value":"=","line":12,"start":261,"end":262},{"type":"T_STRING","context":"normal","value":"'hello'","line":12,"start":263,"end":270},{"type":"T_SEMICOLON","context":"normal","value":";","line":12,"start":270,"end":271},{"type":"T_LET","context":"normal","value":"let","line":13,"start":272,"end":275},{"type":"T_IDENTIFIER","context":"normal","value":"str2","line":13,"start":276,"end":280},{"type":"T_COLON","context":"type","value":":","line":13,"start":280,"end":281},{"type":"T_TYPEOF","context":"type","value":"typeof","line":13,"start":282,"end":288},{"type":"T_IDENTIFIER","context":"type","value":"str1","line":13,"start":289,"end":293},{"type":"T_ASSIGN","context":"normal","value":"=","line":13,"start":294,"end":295},{"type":"T_STRING","context":"normal","value":"'world'","line":13,"start":296,"end":303},{"type":"T_SEMICOLON","context":"normal","value":";","line":13,"start":303,"end":304},{"type":"Line","context":"comment","value":"// Works!","line":13,"start":305,"end":314},{"type":"Line","context":"comment","value":"// $ExpectError","line":14,"start":315,"end":330},{"type":"T_LET","context":"normal","value":"let","line":15,"start":331,"end":334},{"type":"T_IDENTIFIER","context":"normal","value":"str3","line":15,"start":335,"end":339},{"type":"T_COLON","context":"type","value":":","line":15,"start":339,"end":340},{"type":"T_TYPEOF","context":"type","value":"typeof","line":15,"start":341,"end":347},{"type":"T_IDENTIFIER","context":"type","value":"str1","line":15,"start":348,"end":352},{"type":"T_ASSIGN","context":"normal","value":"=","line":15,"start":353,"end":354},{"type":"T_FALSE","context":"normal","value":"false","line":15,"start":355,"end":360},{"type":"T_SEMICOLON","context":"normal","value":";","line":15,"start":360,"end":361},{"type":"Line","context":"comment","value":"// Error!","line":15,"start":364,"end":373}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `'world'` to `num3` because string [1] is incompatible with number [2].","context":"let num3: typeof num1 = 'world'; // Error!","source":"-","start":{"line":5,"column":25,"offset":108},"end":{"line":5,"column":31,"offset":115}}],"operation":null},{"id":"E2","messages":[{"id":"E2M1","description":"Cannot assign `42` to `bool3` because number [1] is incompatible with boolean [2].","context":"let bool3: typeof bool1 = 42; // Error!","source":"-","start":{"line":10,"column":27,"offset":233},"end":{"line":10,"column":28,"offset":235}}],"operation":null},{"id":"E3","messages":[{"id":"E3M1","description":"Cannot assign `false` to `str3` because boolean [1] is incompatible with string [2].","context":"let str3: typeof str1 = false; // Error!","source":"-","start":{"line":15,"column":25,"offset":355},"end":{"line":15,"column":29,"offset":360}}],"operation":null}]}
You can use any value with typeof
:
1
2
3
4
5
6
|
let obj1 = { foo: 1, bar: true, baz: 'three' };
let obj2: typeof obj1 = { foo: 42, bar: false, baz: 'hello' };
let arr1 = [1, 2, 3];
let arr2: typeof arr1 = [3, 2, 1];
|
{"value":"// @flow\nlet obj1 = { foo: 1, bar: true, baz: 'three' };\nlet obj2: typeof obj1 = { foo: 42, bar: false, baz: 'hello' };\n\nlet arr1 = [1, 2, 3];\nlet arr2: typeof arr1 = [3, 2, 1];\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":"obj1","line":2,"start":13,"end":17},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":18,"end":19},{"type":"T_LCURLY","context":"normal","value":"{","line":2,"start":20,"end":21},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":2,"start":22,"end":25},{"type":"T_COLON","context":"normal","value":":","line":2,"start":25,"end":26},{"type":"T_NUMBER","context":"normal","value":"1","line":2,"start":27,"end":28},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":28,"end":29},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":2,"start":30,"end":33},{"type":"T_COLON","context":"normal","value":":","line":2,"start":33,"end":34},{"type":"T_TRUE","context":"normal","value":"true","line":2,"start":35,"end":39},{"type":"T_COMMA","context":"normal","value":",","line":2,"start":39,"end":40},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":2,"start":41,"end":44},{"type":"T_COLON","context":"normal","value":":","line":2,"start":44,"end":45},{"type":"T_STRING","context":"normal","value":"'three'","line":2,"start":46,"end":53},{"type":"T_RCURLY","context":"normal","value":"}","line":2,"start":54,"end":55},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":55,"end":56},{"type":"T_LET","context":"normal","value":"let","line":3,"start":57,"end":60},{"type":"T_IDENTIFIER","context":"normal","value":"obj2","line":3,"start":61,"end":65},{"type":"T_COLON","context":"type","value":":","line":3,"start":65,"end":66},{"type":"T_TYPEOF","context":"type","value":"typeof","line":3,"start":67,"end":73},{"type":"T_IDENTIFIER","context":"type","value":"obj1","line":3,"start":74,"end":78},{"type":"T_ASSIGN","context":"normal","value":"=","line":3,"start":79,"end":80},{"type":"T_LCURLY","context":"normal","value":"{","line":3,"start":81,"end":82},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":3,"start":83,"end":86},{"type":"T_COLON","context":"normal","value":":","line":3,"start":86,"end":87},{"type":"T_NUMBER","context":"normal","value":"42","line":3,"start":88,"end":90},{"type":"T_COMMA","context":"normal","value":",","line":3,"start":90,"end":91},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":3,"start":92,"end":95},{"type":"T_COLON","context":"normal","value":":","line":3,"start":95,"end":96},{"type":"T_FALSE","context":"normal","value":"false","line":3,"start":97,"end":102},{"type":"T_COMMA","context":"normal","value":",","line":3,"start":102,"end":103},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":3,"start":104,"end":107},{"type":"T_COLON","context":"normal","value":":","line":3,"start":107,"end":108},{"type":"T_STRING","context":"normal","value":"'hello'","line":3,"start":109,"end":116},{"type":"T_RCURLY","context":"normal","value":"}","line":3,"start":117,"end":118},{"type":"T_SEMICOLON","context":"normal","value":";","line":3,"start":118,"end":119},{"type":"T_LET","context":"normal","value":"let","line":5,"start":121,"end":124},{"type":"T_IDENTIFIER","context":"normal","value":"arr1","line":5,"start":125,"end":129},{"type":"T_ASSIGN","context":"normal","value":"=","line":5,"start":130,"end":131},{"type":"T_LBRACKET","context":"normal","value":"[","line":5,"start":132,"end":133},{"type":"T_NUMBER","context":"normal","value":"1","line":5,"start":133,"end":134},{"type":"T_COMMA","context":"normal","value":",","line":5,"start":134,"end":135},{"type":"T_NUMBER","context":"normal","value":"2","line":5,"start":136,"end":137},{"type":"T_COMMA","context":"normal","value":",","line":5,"start":137,"end":138},{"type":"T_NUMBER","context":"normal","value":"3","line":5,"start":139,"end":140},{"type":"T_RBRACKET","context":"normal","value":"]","line":5,"start":140,"end":141},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":141,"end":142},{"type":"T_LET","context":"normal","value":"let","line":6,"start":143,"end":146},{"type":"T_IDENTIFIER","context":"normal","value":"arr2","line":6,"start":147,"end":151},{"type":"T_COLON","context":"type","value":":","line":6,"start":151,"end":152},{"type":"T_TYPEOF","context":"type","value":"typeof","line":6,"start":153,"end":159},{"type":"T_IDENTIFIER","context":"type","value":"arr1","line":6,"start":160,"end":164},{"type":"T_ASSIGN","context":"normal","value":"=","line":6,"start":165,"end":166},{"type":"T_LBRACKET","context":"normal","value":"[","line":6,"start":167,"end":168},{"type":"T_NUMBER","context":"normal","value":"3","line":6,"start":168,"end":169},{"type":"T_COMMA","context":"normal","value":",","line":6,"start":169,"end":170},{"type":"T_NUMBER","context":"normal","value":"2","line":6,"start":171,"end":172},{"type":"T_COMMA","context":"normal","value":",","line":6,"start":172,"end":173},{"type":"T_NUMBER","context":"normal","value":"1","line":6,"start":174,"end":175},{"type":"T_RBRACKET","context":"normal","value":"]","line":6,"start":175,"end":176},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":176,"end":177}],"errors":[]}
typeof
inherits behaviors of inference
Flow does all sorts of type inference on your code so that you don’t have to
type annotate anything. Generally, inference avoids getting in your way while
still preventing you from introducing bugs.
But when you use typeof
, you’re taking the results of Flow’s inference and
asserting it as a type. While this can be very useful, it can also lead to some
unexpected results.
For example, when you use literal values in Flow, their inferred type is the
primitive that it belongs to. Thus, the number 42 has the inferred type of
number
. You can see this when you use typeof
.
1
2
3
4
5
6
7
8
9
|
let num1 = 42;
let num2: typeof num1 = 3.14;
let bool1 = true;
let bool2: typeof bool1 = false;
let str1 = 'hello';
let str2: typeof str1 = 'world';
|
{"value":"// @flow\nlet num1 = 42;\nlet num2: typeof num1 = 3.14; // Works!\n\nlet bool1 = true;\nlet bool2: typeof bool1 = false; // Works!\n\nlet str1 = 'hello';\nlet str2: typeof str1 = 'world'; // 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":"num1","line":2,"start":13,"end":17},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":18,"end":19},{"type":"T_NUMBER","context":"normal","value":"42","line":2,"start":20,"end":22},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":22,"end":23},{"type":"T_LET","context":"normal","value":"let","line":3,"start":24,"end":27},{"type":"T_IDENTIFIER","context":"normal","value":"num2","line":3,"start":28,"end":32},{"type":"T_COLON","context":"type","value":":","line":3,"start":32,"end":33},{"type":"T_TYPEOF","context":"type","value":"typeof","line":3,"start":34,"end":40},{"type":"T_IDENTIFIER","context":"type","value":"num1","line":3,"start":41,"end":45},{"type":"T_ASSIGN","context":"normal","value":"=","line":3,"start":46,"end":47},{"type":"T_NUMBER","context":"normal","value":"3.14","line":3,"start":48,"end":52},{"type":"T_SEMICOLON","context":"normal","value":";","line":3,"start":52,"end":53},{"type":"Line","context":"comment","value":"// Works!","line":3,"start":57,"end":66},{"type":"T_LET","context":"normal","value":"let","line":5,"start":68,"end":71},{"type":"T_IDENTIFIER","context":"normal","value":"bool1","line":5,"start":72,"end":77},{"type":"T_ASSIGN","context":"normal","value":"=","line":5,"start":78,"end":79},{"type":"T_TRUE","context":"normal","value":"true","line":5,"start":80,"end":84},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":84,"end":85},{"type":"T_LET","context":"normal","value":"let","line":6,"start":86,"end":89},{"type":"T_IDENTIFIER","context":"normal","value":"bool2","line":6,"start":90,"end":95},{"type":"T_COLON","context":"type","value":":","line":6,"start":95,"end":96},{"type":"T_TYPEOF","context":"type","value":"typeof","line":6,"start":97,"end":103},{"type":"T_IDENTIFIER","context":"type","value":"bool1","line":6,"start":104,"end":109},{"type":"T_ASSIGN","context":"normal","value":"=","line":6,"start":110,"end":111},{"type":"T_FALSE","context":"normal","value":"false","line":6,"start":112,"end":117},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":117,"end":118},{"type":"Line","context":"comment","value":"// Works!","line":6,"start":119,"end":128},{"type":"T_LET","context":"normal","value":"let","line":8,"start":130,"end":133},{"type":"T_IDENTIFIER","context":"normal","value":"str1","line":8,"start":134,"end":138},{"type":"T_ASSIGN","context":"normal","value":"=","line":8,"start":139,"end":140},{"type":"T_STRING","context":"normal","value":"'hello'","line":8,"start":141,"end":148},{"type":"T_SEMICOLON","context":"normal","value":";","line":8,"start":148,"end":149},{"type":"T_LET","context":"normal","value":"let","line":9,"start":150,"end":153},{"type":"T_IDENTIFIER","context":"normal","value":"str2","line":9,"start":154,"end":158},{"type":"T_COLON","context":"type","value":":","line":9,"start":158,"end":159},{"type":"T_TYPEOF","context":"type","value":"typeof","line":9,"start":160,"end":166},{"type":"T_IDENTIFIER","context":"type","value":"str1","line":9,"start":167,"end":171},{"type":"T_ASSIGN","context":"normal","value":"=","line":9,"start":172,"end":173},{"type":"T_STRING","context":"normal","value":"'world'","line":9,"start":174,"end":181},{"type":"T_SEMICOLON","context":"normal","value":";","line":9,"start":181,"end":182},{"type":"Line","context":"comment","value":"// Works!","line":9,"start":183,"end":192}],"errors":[]}
However, this only happens with the inferred type. If you specify the literal
type, it will be used in typeof
.
1
2
3
4
5
6
7
8
9
10
11
12
|
let num1: 42 = 42;
let num2: typeof num1 = 3.14;
let bool1: true = true;
let bool2: typeof bool1 = false;
let str1: 'hello' = 'hello';
let str2: typeof str1 = 'world';
|
Cannot assign `3.14` to `num2` because number [1] is incompatible with number literal `42` [2].
Cannot assign `false` to `bool2` because boolean [1] is incompatible with boolean literal `true` [2].
Cannot assign `'world'` to `str2` because string [1] is incompatible with string literal `hello` [2].
{"value":"// @flow\nlet num1: 42 = 42;\n// $ExpectError\nlet num2: typeof num1 = 3.14; // Error!\n\nlet bool1: true = true;\n// $ExpectError\nlet bool2: typeof bool1 = false; // Error!\n\nlet str1: 'hello' = 'hello';\n// $ExpectError\nlet str2: typeof str1 = 'world'; // 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":"num1","line":2,"start":13,"end":17},{"type":"T_COLON","context":"type","value":":","line":2,"start":17,"end":18},{"type":"T_NUMBER_SINGLETON_TYPE","context":"type","value":"42","line":2,"start":19,"end":21},{"type":"T_ASSIGN","context":"normal","value":"=","line":2,"start":22,"end":23},{"type":"T_NUMBER","context":"normal","value":"42","line":2,"start":24,"end":26},{"type":"T_SEMICOLON","context":"normal","value":";","line":2,"start":26,"end":27},{"type":"Line","context":"comment","value":"// $ExpectError","line":3,"start":28,"end":43},{"type":"T_LET","context":"normal","value":"let","line":4,"start":44,"end":47},{"type":"T_IDENTIFIER","context":"normal","value":"num2","line":4,"start":48,"end":52},{"type":"T_COLON","context":"type","value":":","line":4,"start":52,"end":53},{"type":"T_TYPEOF","context":"type","value":"typeof","line":4,"start":54,"end":60},{"type":"T_IDENTIFIER","context":"type","value":"num1","line":4,"start":61,"end":65},{"type":"T_ASSIGN","context":"normal","value":"=","line":4,"start":66,"end":67},{"type":"T_NUMBER","context":"normal","value":"3.14","line":4,"start":68,"end":72},{"type":"T_SEMICOLON","context":"normal","value":";","line":4,"start":72,"end":73},{"type":"Line","context":"comment","value":"// Error!","line":4,"start":77,"end":86},{"type":"T_LET","context":"normal","value":"let","line":6,"start":88,"end":91},{"type":"T_IDENTIFIER","context":"normal","value":"bool1","line":6,"start":92,"end":97},{"type":"T_COLON","context":"type","value":":","line":6,"start":97,"end":98},{"type":"T_TRUE","context":"type","value":"true","line":6,"start":99,"end":103},{"type":"T_ASSIGN","context":"normal","value":"=","line":6,"start":104,"end":105},{"type":"T_TRUE","context":"normal","value":"true","line":6,"start":106,"end":110},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":110,"end":111},{"type":"Line","context":"comment","value":"// $ExpectError","line":7,"start":112,"end":127},{"type":"T_LET","context":"normal","value":"let","line":8,"start":128,"end":131},{"type":"T_IDENTIFIER","context":"normal","value":"bool2","line":8,"start":132,"end":137},{"type":"T_COLON","context":"type","value":":","line":8,"start":137,"end":138},{"type":"T_TYPEOF","context":"type","value":"typeof","line":8,"start":139,"end":145},{"type":"T_IDENTIFIER","context":"type","value":"bool1","line":8,"start":146,"end":151},{"type":"T_ASSIGN","context":"normal","value":"=","line":8,"start":152,"end":153},{"type":"T_FALSE","context":"normal","value":"false","line":8,"start":154,"end":159},{"type":"T_SEMICOLON","context":"normal","value":";","line":8,"start":159,"end":160},{"type":"Line","context":"comment","value":"// Error!","line":8,"start":161,"end":170},{"type":"T_LET","context":"normal","value":"let","line":10,"start":172,"end":175},{"type":"T_IDENTIFIER","context":"normal","value":"str1","line":10,"start":176,"end":180},{"type":"T_COLON","context":"type","value":":","line":10,"start":180,"end":181},{"type":"T_STRING","context":"type","value":"'hello'","line":10,"start":182,"end":189},{"type":"T_ASSIGN","context":"normal","value":"=","line":10,"start":190,"end":191},{"type":"T_STRING","context":"normal","value":"'hello'","line":10,"start":192,"end":199},{"type":"T_SEMICOLON","context":"normal","value":";","line":10,"start":199,"end":200},{"type":"Line","context":"comment","value":"// $ExpectError","line":11,"start":201,"end":216},{"type":"T_LET","context":"normal","value":"let","line":12,"start":217,"end":220},{"type":"T_IDENTIFIER","context":"normal","value":"str2","line":12,"start":221,"end":225},{"type":"T_COLON","context":"type","value":":","line":12,"start":225,"end":226},{"type":"T_TYPEOF","context":"type","value":"typeof","line":12,"start":227,"end":233},{"type":"T_IDENTIFIER","context":"type","value":"str1","line":12,"start":234,"end":238},{"type":"T_ASSIGN","context":"normal","value":"=","line":12,"start":239,"end":240},{"type":"T_STRING","context":"normal","value":"'world'","line":12,"start":241,"end":248},{"type":"T_SEMICOLON","context":"normal","value":";","line":12,"start":248,"end":249},{"type":"Line","context":"comment","value":"// Error!","line":12,"start":250,"end":259}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `3.14` to `num2` because number [1] is incompatible with number literal `42` [2].","context":"let num2: typeof num1 = 3.14; // Error!","source":"-","start":{"line":4,"column":25,"offset":68},"end":{"line":4,"column":28,"offset":72}}],"operation":null},{"id":"E2","messages":[{"id":"E2M1","description":"Cannot assign `false` to `bool2` because boolean [1] is incompatible with boolean literal `true` [2].","context":"let bool2: typeof bool1 = false; // Error!","source":"-","start":{"line":8,"column":27,"offset":154},"end":{"line":8,"column":31,"offset":159}}],"operation":null},{"id":"E3","messages":[{"id":"E3M1","description":"Cannot assign `'world'` to `str2` because string [1] is incompatible with string literal `hello` [2].","context":"let str2: typeof str1 = 'world'; // Error!","source":"-","start":{"line":12,"column":25,"offset":241},"end":{"line":12,"column":31,"offset":248}}],"operation":null}]}
typeof
inherits behaviors of other types
There are many different types in Flow, some of these types behave differently
than others. These differences make sense for that particular type but not for
others.
When you use typeof
, you’re inserting another type with all of its behaviors.
This can make typeof
seem inconsistent where it is not.
For example, if you use typeof
with a class you need to remember that classes
are nominally typed instead of structurally typed. So that two classes with
the same exact shape are not considered equivalent.
1
2
3
4
5
6
7
8
9
10
11
12
|
class MyClass {
method(val: number) { }
}
class YourClass {
method(val: number) { }
}
let test1: typeof MyClass = YourClass;
let test2: typeof MyClass = MyClass;
|
Cannot assign `YourClass` to `test1` because `YourClass` [1] is incompatible with `MyClass` [2].
{"value":"// @flow\nclass MyClass {\n method(val: number) { /* ... */ }\n}\n\nclass YourClass {\n method(val: number) { /* ... */ }\n}\n\n// $ExpectError\nlet test1: typeof MyClass = YourClass; // Error!\nlet test2: typeof MyClass = MyClass; // Works!\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_CLASS","context":"normal","value":"class","line":2,"start":9,"end":14},{"type":"T_IDENTIFIER","context":"normal","value":"MyClass","line":2,"start":15,"end":22},{"type":"T_LCURLY","context":"normal","value":"{","line":2,"start":23,"end":24},{"type":"T_IDENTIFIER","context":"normal","value":"method","line":3,"start":27,"end":33},{"type":"T_LPAREN","context":"normal","value":"(","line":3,"start":33,"end":34},{"type":"T_IDENTIFIER","context":"normal","value":"val","line":3,"start":34,"end":37},{"type":"T_COLON","context":"type","value":":","line":3,"start":37,"end":38},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":3,"start":39,"end":45},{"type":"T_RPAREN","context":"normal","value":")","line":3,"start":45,"end":46},{"type":"T_LCURLY","context":"normal","value":"{","line":3,"start":47,"end":48},{"type":"Block","context":"comment","value":"/* ... */","line":3,"start":49,"end":58},{"type":"T_RCURLY","context":"normal","value":"}","line":3,"start":59,"end":60},{"type":"T_RCURLY","context":"normal","value":"}","line":4,"start":61,"end":62},{"type":"T_CLASS","context":"normal","value":"class","line":6,"start":64,"end":69},{"type":"T_IDENTIFIER","context":"normal","value":"YourClass","line":6,"start":70,"end":79},{"type":"T_LCURLY","context":"normal","value":"{","line":6,"start":80,"end":81},{"type":"T_IDENTIFIER","context":"normal","value":"method","line":7,"start":84,"end":90},{"type":"T_LPAREN","context":"normal","value":"(","line":7,"start":90,"end":91},{"type":"T_IDENTIFIER","context":"normal","value":"val","line":7,"start":91,"end":94},{"type":"T_COLON","context":"type","value":":","line":7,"start":94,"end":95},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":7,"start":96,"end":102},{"type":"T_RPAREN","context":"normal","value":")","line":7,"start":102,"end":103},{"type":"T_LCURLY","context":"normal","value":"{","line":7,"start":104,"end":105},{"type":"Block","context":"comment","value":"/* ... */","line":7,"start":106,"end":115},{"type":"T_RCURLY","context":"normal","value":"}","line":7,"start":116,"end":117},{"type":"T_RCURLY","context":"normal","value":"}","line":8,"start":118,"end":119},{"type":"Line","context":"comment","value":"// $ExpectError","line":10,"start":121,"end":136},{"type":"T_LET","context":"normal","value":"let","line":11,"start":137,"end":140},{"type":"T_IDENTIFIER","context":"normal","value":"test1","line":11,"start":141,"end":146},{"type":"T_COLON","context":"type","value":":","line":11,"start":146,"end":147},{"type":"T_TYPEOF","context":"type","value":"typeof","line":11,"start":148,"end":154},{"type":"T_IDENTIFIER","context":"type","value":"MyClass","line":11,"start":155,"end":162},{"type":"T_ASSIGN","context":"normal","value":"=","line":11,"start":163,"end":164},{"type":"T_IDENTIFIER","context":"normal","value":"YourClass","line":11,"start":165,"end":174},{"type":"T_SEMICOLON","context":"normal","value":";","line":11,"start":174,"end":175},{"type":"Line","context":"comment","value":"// Error!","line":11,"start":176,"end":185},{"type":"T_LET","context":"normal","value":"let","line":12,"start":186,"end":189},{"type":"T_IDENTIFIER","context":"normal","value":"test2","line":12,"start":190,"end":195},{"type":"T_COLON","context":"type","value":":","line":12,"start":195,"end":196},{"type":"T_TYPEOF","context":"type","value":"typeof","line":12,"start":197,"end":203},{"type":"T_IDENTIFIER","context":"type","value":"MyClass","line":12,"start":204,"end":211},{"type":"T_ASSIGN","context":"normal","value":"=","line":12,"start":212,"end":213},{"type":"T_IDENTIFIER","context":"normal","value":"MyClass","line":12,"start":214,"end":221},{"type":"T_SEMICOLON","context":"normal","value":";","line":12,"start":221,"end":222},{"type":"Line","context":"comment","value":"// Works!","line":12,"start":225,"end":234}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot assign `YourClass` to `test1` because `YourClass` [1] is incompatible with `MyClass` [2].","context":"let test1: typeof MyClass = YourClass; // Error!","source":"-","start":{"line":11,"column":29,"offset":165},"end":{"line":11,"column":37,"offset":174}}],"operation":null}]}