-
-
Save goodmind/3020f43331c9c845b5f417d77e29c4c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
A collection of tests where Flow and TypeScript might have different behavior | |
Some tests are borrowed from https://github.com/vkurchatkin/typescript-vs-flow | |
Some tests now have the same behavior as the new versions of Flow/TS have fixed the bugs and improved type safety | |
*/ | |
/* Accessing unknown properties on objects */ | |
/* --------------------------------------- */ | |
// https://github.com/facebook/flow/issues/106 | |
const a = {}; | |
a.foo.bar; // TS — error, Flow — ok | |
/* Accessing unknown properties on functions */ | |
/* ----------------------------------------- */ | |
const e = (): void => { } | |
e.foo // TS — error, Flow — ok | |
/* Union refinement */ | |
/* ---------------- */ | |
type Foo = { type: 'foo' , foo: string }; | |
type Bar = { type: 'bar' , bar: string }; | |
type MyType = Foo | Bar; | |
export function test(t: MyType) { | |
if (t.type === 'foo') { | |
console.log(t.foo); // Flow — no error, TS — no error | |
console.log(t.bar) // Flow — error, TS — error | |
} | |
} | |
/* Union refinement with typed return */ | |
/* ---------------------------------- */ | |
// https://github.com/facebook/flow/issues/4639 | |
type Foo = {| foo: string |}; | |
type Bar = {| bar: string |}; | |
function getFooOrNull(u: Foo | Bar): ?Foo { | |
return typeof u.foo === "undefined" ? null : u; // TS — error, Flow — error | |
return u.foo === undefined ? null : u; // TS — error, Flow — error | |
return "foo" in u ? null : u; // TS — error, Flow — error | |
} | |
/* Invocations with invalid types */ | |
/* ------------------------------ */ | |
export function test1(obj: { foo: string }) { | |
console.log(obj.foo); | |
} | |
test1(null); // Flow — error, TS — error | |
test1(undefined); // Flow — error, TS — error | |
export function test2(num: number) { | |
console.log(num); | |
} | |
test2(null); // Flow — error, TS — error | |
test2(undefined); // Flow — error, TS — error | |
export function test3(): number { | |
return; // Flow — error, TS — error | |
} | |
/* "enums" validity */ | |
/* ---------------- */ | |
type Direction = 1 | 2; | |
export function test(v: Direction) { } | |
test(100); // Flow — error, TS — error | |
/* "enums" validity with typeof */ | |
/* ---------------------------- */ | |
const x = 1; | |
const y = 2; | |
type Direction = typeof x | typeof y; | |
export function test(v: Direction) { } | |
test(100); // Flow — no error, TS — error | |
/* Dynamic refinement */ | |
/* ------------------ */ | |
type A = { a: string | number }; | |
type B = { a: string }; | |
export function test(a: A) { | |
a.a = 4; | |
} | |
const b: B = { a: 'foo' }; | |
test(b); // Flow — error, TS — ok | |
b.a.toLowerCase(); | |
/* Dynamic refinement #2 */ | |
/* --------------------- */ | |
function print(x: number | string) { | |
console.log(x); | |
} | |
export function test(foobar: boolean) { | |
let x = 100; | |
// x is an open type, so you can expand it | |
// x is number here | |
if (foobar) { | |
// x is string here | |
x = 'Invalid'; // Flow — ok, TS — error | |
} | |
// x is number | string here | |
print(x); // no error | |
} | |
/* Classes */ | |
/* ------- */ | |
class Animal {} | |
class Cat extends Animal { | |
meow() {} | |
} | |
class Dog {} | |
export function test(animals: Animal[]) { | |
animals.push(new Dog()); // flow — error, TS — no error | |
} | |
const cats: Cat[] = []; | |
test(cats); // flow — error, TS — no error | |
cats.forEach(cat => cat.meow()); | |
/* Computed key as generic */ | |
/* ----------------------- */ | |
// TS | |
declare function foo<T extends string>(myEnum: T, pattern: {[key in T]: string}): T; | |
const x = foo('bar', { bar: '' }); // TS — no error | |
const y = foo('foo', { bar: '' }); // TS — error | |
// Flow | |
declare function foo<T: string>(myEnum: T, pattern: {[key: T]: string}): T; | |
const x = foo('bar', { bar: '' }); // Flow — no error | |
const y = foo('foo', { bar: '' }); // Flow — no error | |
/* Readonly property operator assignment */ | |
/* ------------------------------------- */ | |
// TS | |
const foo: {readonly bar: number} = {bar: 1} | |
foo.bar += 1 // TS - error | |
// Flow | |
const foo: {+bar: number} = {bar: 1} | |
foo.bar += 1 // Flow - no error |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment