Flow supports a comment-based syntax, which makes it possible to use Flow
without having to compile your files.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/*::
type MyAlias = {
foo: number,
bar: boolean,
baz: string,
};
*/
function method(value /*: MyAlias */) /*: boolean */ {
return value.bar;
}
method({ foo: 1, bar: true, baz: ["oops"] });
|
Cannot call `method` with object literal bound to `value` because array literal [1] is incompatible with string [2] in property `baz`. [incompatible-call]
{"value":"// @flow\n\n/*::\ntype MyAlias = {\n foo: number,\n bar: boolean,\n baz: string,\n};\n*/\n\nfunction method(value /*: MyAlias */) /*: boolean */ {\n return value.bar;\n}\n\nmethod({ foo: 1, bar: true, baz: [\"oops\"] });\n","tokens":[{"type":"Line","context":"comment","value":"// @flow","line":1,"start":0,"end":8},{"type":"T_TYPE","context":"normal","value":"type","line":4,"start":15,"end":19},{"type":"T_IDENTIFIER","context":"type","value":"MyAlias","line":4,"start":20,"end":27},{"type":"T_ASSIGN","context":"type","value":"=","line":4,"start":28,"end":29},{"type":"T_LCURLY","context":"type","value":"{","line":4,"start":30,"end":31},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":5,"start":34,"end":37},{"type":"T_COLON","context":"type","value":":","line":5,"start":37,"end":38},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":5,"start":39,"end":45},{"type":"T_COMMA","context":"type","value":",","line":5,"start":45,"end":46},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":6,"start":49,"end":52},{"type":"T_COLON","context":"type","value":":","line":6,"start":52,"end":53},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":6,"start":54,"end":61},{"type":"T_COMMA","context":"type","value":",","line":6,"start":61,"end":62},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":7,"start":65,"end":68},{"type":"T_COLON","context":"type","value":":","line":7,"start":68,"end":69},{"type":"T_STRING_TYPE","context":"type","value":"string","line":7,"start":70,"end":76},{"type":"T_COMMA","context":"type","value":",","line":7,"start":76,"end":77},{"type":"T_RCURLY","context":"type","value":"}","line":8,"start":78,"end":79},{"type":"T_SEMICOLON","context":"normal","value":";","line":8,"start":79,"end":80},{"type":"T_FUNCTION","context":"normal","value":"function","line":11,"start":85,"end":93},{"type":"T_IDENTIFIER","context":"normal","value":"method","line":11,"start":94,"end":100},{"type":"T_LPAREN","context":"normal","value":"(","line":11,"start":100,"end":101},{"type":"T_IDENTIFIER","context":"normal","value":"value","line":11,"start":101,"end":106},{"type":"T_COLON","context":"type","value":":","line":11,"start":107,"end":110},{"type":"T_IDENTIFIER","context":"type","value":"MyAlias","line":11,"start":111,"end":118},{"type":"T_RPAREN","context":"normal","value":")","line":11,"start":121,"end":122},{"type":"T_COLON","context":"type","value":":","line":11,"start":123,"end":126},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":11,"start":127,"end":134},{"type":"T_LCURLY","context":"normal","value":"{","line":11,"start":138,"end":139},{"type":"T_RETURN","context":"normal","value":"return","line":12,"start":142,"end":148},{"type":"T_IDENTIFIER","context":"normal","value":"value","line":12,"start":149,"end":154},{"type":"T_PERIOD","context":"normal","value":".","line":12,"start":154,"end":155},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":12,"start":155,"end":158},{"type":"T_SEMICOLON","context":"normal","value":";","line":12,"start":158,"end":159},{"type":"T_RCURLY","context":"normal","value":"}","line":13,"start":160,"end":161},{"type":"T_IDENTIFIER","context":"normal","value":"method","line":15,"start":163,"end":169},{"type":"T_LPAREN","context":"normal","value":"(","line":15,"start":169,"end":170},{"type":"T_LCURLY","context":"normal","value":"{","line":15,"start":170,"end":171},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":15,"start":172,"end":175},{"type":"T_COLON","context":"normal","value":":","line":15,"start":175,"end":176},{"type":"T_NUMBER","context":"normal","value":"1","line":15,"start":177,"end":178},{"type":"T_COMMA","context":"normal","value":",","line":15,"start":178,"end":179},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":15,"start":180,"end":183},{"type":"T_COLON","context":"normal","value":":","line":15,"start":183,"end":184},{"type":"T_TRUE","context":"normal","value":"true","line":15,"start":185,"end":189},{"type":"T_COMMA","context":"normal","value":",","line":15,"start":189,"end":190},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":15,"start":191,"end":194},{"type":"T_COLON","context":"normal","value":":","line":15,"start":194,"end":195},{"type":"T_LBRACKET","context":"normal","value":"[","line":15,"start":196,"end":197},{"type":"T_STRING","context":"normal","value":"\"oops\"","line":15,"start":197,"end":203},{"type":"T_RBRACKET","context":"normal","value":"]","line":15,"start":203,"end":204},{"type":"T_RCURLY","context":"normal","value":"}","line":15,"start":205,"end":206},{"type":"T_RPAREN","context":"normal","value":")","line":15,"start":206,"end":207},{"type":"T_SEMICOLON","context":"normal","value":";","line":15,"start":207,"end":208}],"errors":[{"id":"E1","messages":[{"id":"E1M1","description":"Cannot call `method` with object literal bound to `value` because array literal [1] is incompatible with string [2] in property `baz`. [incompatible-call]","context":"method({ foo: 1, bar: true, baz: [\"oops\"] });","source":"-","start":{"line":15,"column":34,"offset":196},"end":{"line":15,"column":41,"offset":204}}],"operation":null}]}
These comments allow Flow to work in plain JavaScript files without any
additional work.
There are two primary pieces of the syntax: type includes and type annotations.
If you want to have Flow treat a comment as if it were normal syntax, you can
do so by adding a double colon ::
to the start of the comment.
1
2
3
4
5
6
7
8
9
10
11
|
/*::
type Foo = {
foo: number,
bar: boolean,
baz: string
};
*/
class MyClass {
/*:: prop: string; */
}
|
{"value":"/*::\ntype Foo = {\n foo: number,\n bar: boolean,\n baz: string\n};\n*/\n\nclass MyClass {\n /*:: prop: string; */\n}\n","tokens":[{"type":"T_TYPE","context":"normal","value":"type","line":2,"start":5,"end":9},{"type":"T_IDENTIFIER","context":"type","value":"Foo","line":2,"start":10,"end":13},{"type":"T_ASSIGN","context":"type","value":"=","line":2,"start":14,"end":15},{"type":"T_LCURLY","context":"type","value":"{","line":2,"start":16,"end":17},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":3,"start":20,"end":23},{"type":"T_COLON","context":"type","value":":","line":3,"start":23,"end":24},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":3,"start":25,"end":31},{"type":"T_COMMA","context":"type","value":",","line":3,"start":31,"end":32},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":4,"start":35,"end":38},{"type":"T_COLON","context":"type","value":":","line":4,"start":38,"end":39},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":4,"start":40,"end":47},{"type":"T_COMMA","context":"type","value":",","line":4,"start":47,"end":48},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":5,"start":51,"end":54},{"type":"T_COLON","context":"type","value":":","line":5,"start":54,"end":55},{"type":"T_STRING_TYPE","context":"type","value":"string","line":5,"start":56,"end":62},{"type":"T_RCURLY","context":"type","value":"}","line":6,"start":63,"end":64},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":64,"end":65},{"type":"T_CLASS","context":"normal","value":"class","line":9,"start":70,"end":75},{"type":"T_IDENTIFIER","context":"normal","value":"MyClass","line":9,"start":76,"end":83},{"type":"T_LCURLY","context":"normal","value":"{","line":9,"start":84,"end":85},{"type":"T_IDENTIFIER","context":"normal","value":"prop","line":10,"start":93,"end":97},{"type":"T_COLON","context":"type","value":":","line":10,"start":97,"end":98},{"type":"T_STRING_TYPE","context":"type","value":"string","line":10,"start":99,"end":105},{"type":"T_SEMICOLON","context":"normal","value":";","line":10,"start":105,"end":106},{"type":"T_RCURLY","context":"normal","value":"}","line":11,"start":110,"end":111}],"errors":[]}
This includes the code into the syntax that Flow sees.
1
2
3
4
5
6
7
8
9
|
type Foo = {
foo: number,
bar: boolean,
baz: string
};
class MyClass {
prop: string;
}
|
{"value":"type Foo = {\n foo: number,\n bar: boolean,\n baz: string\n};\n\nclass MyClass {\n prop: string;\n}\n","tokens":[{"type":"T_TYPE","context":"normal","value":"type","line":1,"start":0,"end":4},{"type":"T_IDENTIFIER","context":"type","value":"Foo","line":1,"start":5,"end":8},{"type":"T_ASSIGN","context":"type","value":"=","line":1,"start":9,"end":10},{"type":"T_LCURLY","context":"type","value":"{","line":1,"start":11,"end":12},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":2,"start":15,"end":18},{"type":"T_COLON","context":"type","value":":","line":2,"start":18,"end":19},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":2,"start":20,"end":26},{"type":"T_COMMA","context":"type","value":",","line":2,"start":26,"end":27},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":3,"start":30,"end":33},{"type":"T_COLON","context":"type","value":":","line":3,"start":33,"end":34},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":3,"start":35,"end":42},{"type":"T_COMMA","context":"type","value":",","line":3,"start":42,"end":43},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":4,"start":46,"end":49},{"type":"T_COLON","context":"type","value":":","line":4,"start":49,"end":50},{"type":"T_STRING_TYPE","context":"type","value":"string","line":4,"start":51,"end":57},{"type":"T_RCURLY","context":"type","value":"}","line":5,"start":58,"end":59},{"type":"T_SEMICOLON","context":"normal","value":";","line":5,"start":59,"end":60},{"type":"T_CLASS","context":"normal","value":"class","line":7,"start":62,"end":67},{"type":"T_IDENTIFIER","context":"normal","value":"MyClass","line":7,"start":68,"end":75},{"type":"T_LCURLY","context":"normal","value":"{","line":7,"start":76,"end":77},{"type":"T_IDENTIFIER","context":"normal","value":"prop","line":8,"start":80,"end":84},{"type":"T_COLON","context":"type","value":":","line":8,"start":84,"end":85},{"type":"T_STRING_TYPE","context":"type","value":"string","line":8,"start":86,"end":92},{"type":"T_SEMICOLON","context":"normal","value":";","line":8,"start":92,"end":93},{"type":"T_RCURLY","context":"normal","value":"}","line":9,"start":94,"end":95}],"errors":[]}
But JavaScript ignores these comments, so all it has is the valid syntax.
{"value":"class MyClass {\n\n}\n","tokens":[{"type":"T_CLASS","context":"normal","value":"class","line":1,"start":0,"end":5},{"type":"T_IDENTIFIER","context":"normal","value":"MyClass","line":1,"start":6,"end":13},{"type":"T_LCURLY","context":"normal","value":"{","line":1,"start":14,"end":15},{"type":"T_RCURLY","context":"normal","value":"}","line":3,"start":17,"end":18}],"errors":[]}
This syntax is also available in a flow-include
form.
1
2
3
4
5
6
7
8
9
10
11
|
/*flow-include
type Foo = {
foo: number,
bar: boolean,
baz: string
};
*/
class MyClass {
/*flow-include prop: string; */
}
|
{"value":"/*flow-include\ntype Foo = {\n foo: number,\n bar: boolean,\n baz: string\n};\n*/\n\nclass MyClass {\n /*flow-include prop: string; */\n}\n","tokens":[{"type":"T_TYPE","context":"normal","value":"type","line":2,"start":15,"end":19},{"type":"T_IDENTIFIER","context":"type","value":"Foo","line":2,"start":20,"end":23},{"type":"T_ASSIGN","context":"type","value":"=","line":2,"start":24,"end":25},{"type":"T_LCURLY","context":"type","value":"{","line":2,"start":26,"end":27},{"type":"T_IDENTIFIER","context":"normal","value":"foo","line":3,"start":30,"end":33},{"type":"T_COLON","context":"type","value":":","line":3,"start":33,"end":34},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":3,"start":35,"end":41},{"type":"T_COMMA","context":"type","value":",","line":3,"start":41,"end":42},{"type":"T_IDENTIFIER","context":"normal","value":"bar","line":4,"start":45,"end":48},{"type":"T_COLON","context":"type","value":":","line":4,"start":48,"end":49},{"type":"T_BOOLEAN_TYPE","context":"type","value":"boolean","line":4,"start":50,"end":57},{"type":"T_COMMA","context":"type","value":",","line":4,"start":57,"end":58},{"type":"T_IDENTIFIER","context":"normal","value":"baz","line":5,"start":61,"end":64},{"type":"T_COLON","context":"type","value":":","line":5,"start":64,"end":65},{"type":"T_STRING_TYPE","context":"type","value":"string","line":5,"start":66,"end":72},{"type":"T_RCURLY","context":"type","value":"}","line":6,"start":73,"end":74},{"type":"T_SEMICOLON","context":"normal","value":";","line":6,"start":74,"end":75},{"type":"T_CLASS","context":"normal","value":"class","line":9,"start":80,"end":85},{"type":"T_IDENTIFIER","context":"normal","value":"MyClass","line":9,"start":86,"end":93},{"type":"T_LCURLY","context":"normal","value":"{","line":9,"start":94,"end":95},{"type":"T_IDENTIFIER","context":"normal","value":"prop","line":10,"start":113,"end":117},{"type":"T_COLON","context":"type","value":":","line":10,"start":117,"end":118},{"type":"T_STRING_TYPE","context":"type","value":"string","line":10,"start":119,"end":125},{"type":"T_SEMICOLON","context":"normal","value":";","line":10,"start":125,"end":126},{"type":"T_RCURLY","context":"normal","value":"}","line":11,"start":130,"end":131}],"errors":[]}
Instead of typing out a full include every time, you can also use the type
annotation shorthand with a single colon :
at the start of the comment.
1
2
3
|
function method(param /*: string */) /*: number */ {
}
|
{"value":"function method(param /*: string */) /*: number */ {\n // ...\n}\n","tokens":[{"type":"T_FUNCTION","context":"normal","value":"function","line":1,"start":0,"end":8},{"type":"T_IDENTIFIER","context":"normal","value":"method","line":1,"start":9,"end":15},{"type":"T_LPAREN","context":"normal","value":"(","line":1,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"param","line":1,"start":16,"end":21},{"type":"T_COLON","context":"type","value":":","line":1,"start":22,"end":25},{"type":"T_STRING_TYPE","context":"type","value":"string","line":1,"start":26,"end":32},{"type":"T_RPAREN","context":"normal","value":")","line":1,"start":35,"end":36},{"type":"T_COLON","context":"type","value":":","line":1,"start":37,"end":40},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":1,"start":41,"end":47},{"type":"T_LCURLY","context":"normal","value":"{","line":1,"start":51,"end":52},{"type":"Line","context":"comment","value":"// ...","line":2,"start":55,"end":61},{"type":"T_RCURLY","context":"normal","value":"}","line":3,"start":62,"end":63}],"errors":[]}
This would be the same as including a type annotation inside an include
comment.
1
2
3
|
function method(param /*:: : string */) /*:: : number */ {
}
|
{"value":"function method(param /*:: : string */) /*:: : number */ {\n // ...\n}\n","tokens":[{"type":"T_FUNCTION","context":"normal","value":"function","line":1,"start":0,"end":8},{"type":"T_IDENTIFIER","context":"normal","value":"method","line":1,"start":9,"end":15},{"type":"T_LPAREN","context":"normal","value":"(","line":1,"start":15,"end":16},{"type":"T_IDENTIFIER","context":"normal","value":"param","line":1,"start":16,"end":21},{"type":"T_COLON","context":"type","value":":","line":1,"start":27,"end":28},{"type":"T_STRING_TYPE","context":"type","value":"string","line":1,"start":29,"end":35},{"type":"T_RPAREN","context":"normal","value":")","line":1,"start":38,"end":39},{"type":"T_COLON","context":"type","value":":","line":1,"start":45,"end":46},{"type":"T_NUMBER_TYPE","context":"type","value":"number","line":1,"start":47,"end":53},{"type":"T_LCURLY","context":"normal","value":"{","line":1,"start":57,"end":58},{"type":"Line","context":"comment","value":"// ...","line":2,"start":61,"end":67},{"type":"T_RCURLY","context":"normal","value":"}","line":3,"start":68,"end":69}],"errors":[]}
Note: If you want to use optional function parameters you’ll need to use
the include comment form.
Special thanks to: Jarno Rantanen for
building flotate and supporting us
merging his syntax upstream into Flow.