├── .gitignore ├── README.md ├── flow ├── .flowconfig ├── 1.js ├── 2.js ├── 3.js ├── 4.js ├── 5.js ├── 6.js └── 7.js ├── package.json ├── ts ├── 1.ts ├── 2.ts ├── 3.ts ├── 4.ts ├── 5.ts ├── 6.ts └── 7.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | ts-built 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # typescript-vs-flow 2 | 3 | A collection of snippets, where Flow does better job than TypeScript. 4 | 5 | ## TLDR 6 | 7 | Flow is more flexible and provides much more safety than TypeScript at 8 | the same time. 9 | 10 | ## P.S. 11 | 12 | Use TypeScript, it's not worth it 13 | -------------------------------------------------------------------------------- /flow/.flowconfig: -------------------------------------------------------------------------------- 1 | [options] 2 | suppress_comment=\\(.\\|\n\\)*\\$ExpectError 3 | -------------------------------------------------------------------------------- /flow/1.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // exactly the same code as 1.ts 4 | 5 | export function test1(obj: { foo: string }) { 6 | console.log(obj.foo); 7 | } 8 | 9 | export function test2(num: number) { 10 | console.log(num); 11 | } 12 | 13 | // $ExpectError 14 | test1(null); // error 15 | 16 | // $ExpectError 17 | test1(undefined); // error 18 | 19 | // $ExpectError 20 | test2(null); // error 21 | 22 | // $ExpectError 23 | test2(undefined); // error 24 | 25 | export function test3(): number { 26 | // $ExpectError 27 | return; // error 28 | } 29 | -------------------------------------------------------------------------------- /flow/2.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // exactly the same code as 2.ts 4 | 5 | type Foo = { type: 'foo' , foo: string }; 6 | type Bar = { type: 'bar' , bar: string }; 7 | type MyType = Foo | Bar; 8 | 9 | export function test(t: MyType) { 10 | if (t.type === 'foo') { 11 | // Flow knows, that t is Foo 12 | console.log(t.foo); // no error 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /flow/3.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // exactly the same code as 3.ts 4 | 5 | type Foo = { type: 'foo' , foo: string }; 6 | type Bar = { type: 'bar' , bar: string }; 7 | type MyType = Foo | Bar; 8 | 9 | 10 | 11 | export function test(t: MyType) { 12 | if (t.type === 'foo') { 13 | // $ExpectError 14 | console.log(t.bar) // error 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /flow/4.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // Flow doesn't have special syntax for enums 4 | const Up = 1; 5 | const Down = 2; 6 | const Left = 3; 7 | const Right = 4; 8 | 9 | type Direction = 10 | | typeof Up 11 | | typeof Down 12 | | typeof Left 13 | | typeof Right 14 | ; 15 | 16 | export function test(v: Direction) { 17 | } 18 | 19 | test(100); // error 20 | -------------------------------------------------------------------------------- /flow/5.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | // exactly the same code as 5.ts 4 | 5 | type A = { 6 | a: string | number 7 | }; 8 | 9 | type B = { 10 | a: string 11 | }; 12 | 13 | export function test(a: A) { 14 | a.a = 4; 15 | } 16 | 17 | 18 | const b: B = { a: 'foo' }; 19 | // $ExpectError 20 | test(b); // error 21 | b.a.toLowerCase(); 22 | -------------------------------------------------------------------------------- /flow/6.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | function print(x: number | string) { 4 | console.log(x); 5 | } 6 | 7 | export function test(foobar: boolean) { 8 | let x = 100; 9 | // x is an open type, so you can expand it 10 | // x is number here 11 | if (foobar) { 12 | x = 'Invalid'; // this is ok 13 | // x is string here 14 | } 15 | 16 | // x is number | string here 17 | print(x); // no error 18 | } 19 | -------------------------------------------------------------------------------- /flow/7.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | class Animal {} 4 | class Cat extends Animal { 5 | meow() {} 6 | } 7 | class Dog {} 8 | 9 | export function test(animals: Animal[]) { 10 | // $ExpectError 11 | animals.push(new Dog()); 12 | } 13 | 14 | const cats: Cat[] = []; 15 | 16 | // $ExpectError 17 | test(cats); 18 | 19 | cats.forEach(cat => cat.meow()); // runtime error 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-vs-flow", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "compile": "tsc --strictNullChecks", 8 | "check": "flow check flow" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "flow-bin": "^0.57.3", 14 | "typescript": "^2.5.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ts/1.ts: -------------------------------------------------------------------------------- 1 | export function test1(obj: { foo: string }) { 2 | console.log(obj.foo); 3 | } 4 | 5 | export function test2(num: number) { 6 | console.log(num); 7 | } 8 | 9 | // Typescript 2 with --strictNullChecks catches these errors 10 | test1(null); 11 | test1(undefined); 12 | test2(null); 13 | test2(undefined); 14 | 15 | 16 | export function test3(): number { 17 | return; 18 | } 19 | -------------------------------------------------------------------------------- /ts/2.ts: -------------------------------------------------------------------------------- 1 | type Foo = { type: 'foo' , foo: string }; 2 | type Bar = { type: 'bar' , bar: string }; 3 | type MyType = Foo | Bar; 4 | 5 | export function test(t: MyType) { 6 | if (t.type === 'foo') { 7 | // Typescript 2 knows, that t is Foo 8 | console.log(t.foo); // no error 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ts/3.ts: -------------------------------------------------------------------------------- 1 | type Foo = { type: 'foo' , foo: string }; 2 | type Bar = { type: 'bar' , bar: string }; 3 | type MyType = Foo | Bar; 4 | 5 | 6 | export function test(t: MyType) { 7 | if (t.type === 'foo') { 8 | console.log(t.bar) // error, as expected 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ts/4.ts: -------------------------------------------------------------------------------- 1 | 2 | enum Direction { 3 | Up = 1, 4 | Down, 5 | Left, 6 | Right 7 | } 8 | 9 | export function test(v: Direction) { 10 | } 11 | 12 | // Typescript allows to pass any number instead of enum value 13 | test(100); 14 | -------------------------------------------------------------------------------- /ts/5.ts: -------------------------------------------------------------------------------- 1 | type A = { 2 | a: string | number 3 | }; 4 | 5 | type B = { 6 | a: string 7 | }; 8 | 9 | export function test(a: A) { 10 | a.a = 4; 11 | } 12 | 13 | 14 | const b: B = { a: 'foo' }; 15 | test(b); // TypeScript allows to do this, but it's unsafe 16 | b.a.toLowerCase(); // Runtime error 17 | -------------------------------------------------------------------------------- /ts/6.ts: -------------------------------------------------------------------------------- 1 | function print(x: number | string) { 2 | console.log(x); 3 | } 4 | 5 | export function test(foobar: boolean) { 6 | let x = 100; // Typescript immediately thinks that x is number 7 | 8 | if (foobar) { 9 | x = 'Invalid'; // error 10 | } 11 | 12 | print(x); 13 | } 14 | -------------------------------------------------------------------------------- /ts/7.ts: -------------------------------------------------------------------------------- 1 | class Animal {} 2 | class Cat extends Animal { 3 | meow() {} 4 | } 5 | class Dog {} 6 | 7 | export function test(animals: Animal[]) { 8 | animals.push(new Dog()); 9 | } 10 | 11 | const cats: Cat[] = []; 12 | 13 | test(cats); 14 | 15 | cats.forEach(cat => cat.meow()); // runtime error 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES5", 5 | "outDir": "ts-built", 6 | "rootDir": "ts", 7 | "moduleResolution": "node" 8 | } 9 | } 10 | --------------------------------------------------------------------------------