{"id":13395245,"url":"https://github.com/niieani/typescript-vs-flowtype","last_synced_at":"2025-05-16T00:00:28.079Z","repository":{"id":50726299,"uuid":"77182811","full_name":"niieani/typescript-vs-flowtype","owner":"niieani","description":"Differences between Flowtype and TypeScript -- syntax and usability","archived":false,"fork":false,"pushed_at":"2020-02-29T23:53:44.000Z","size":123,"stargazers_count":1730,"open_issues_count":25,"forks_count":79,"subscribers_count":37,"default_branch":"master","last_synced_at":"2025-05-08T18:53:26.492Z","etag":null,"topics":["comparison","documentation","flow","flowtype","hacktoberfest","javascript-tools","reference","typescript","typing"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niieani.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-22T23:27:18.000Z","updated_at":"2025-05-08T08:27:43.000Z","dependencies_parsed_at":"2022-08-27T07:10:36.753Z","dependency_job_id":null,"html_url":"https://github.com/niieani/typescript-vs-flowtype","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Ftypescript-vs-flowtype","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Ftypescript-vs-flowtype/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Ftypescript-vs-flowtype/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niieani%2Ftypescript-vs-flowtype/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niieani","download_url":"https://codeload.github.com/niieani/typescript-vs-flowtype/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254442854,"owners_count":22071877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["comparison","documentation","flow","flowtype","hacktoberfest","javascript-tools","reference","typescript","typing"],"created_at":"2024-07-30T17:01:47.570Z","updated_at":"2025-05-16T00:00:26.621Z","avatar_url":"https://github.com/niieani.png","language":null,"funding_links":[],"categories":["Others","documentation","📦 Legacy \u0026 Inactive Projects"],"sub_categories":[],"readme":"# TypeScript vs Flow\n\nBoth TypeScript and Flow are very similar products and they share most of their syntax with some important differences.\nIn this document I've tried to compile the list of differences and similarities between Flowtype and TypeScript -- specifically the syntax, usage and usability.\n\n## Disclaimer\n\n*This document might be incomplete and/or contain mistakes and was last updated to describe **TypeScript 3.7.0** and **Flow 0.101**.*\n\n*I'm maintaining it in my spare time, so if you find mistakes, or learn about latest additions to either project, please help keep this repo up-to-date by contributing and [editing this page](https://github.com/niieani/typescript-vs-flowtype/edit/master/README.md).*\n\n*Thanks!*\n\n# Differences in usage and usability\n\nSome of these differences are subjective (e.g. error readability), and I'd love to make this as scientific as possible — so please [contribute](https://github.com/niieani/typescript-vs-flowtype/edit/master/README.md) to make it better. :)\n\n|   | TypeScript            | Flow |\n|---|------------------|--------|\n| Leading Design Goal / North Star | identify errors in programs through [a balance between correctness and productivity](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals) | enforce type soundness / safety |\n| IDE integrations | top-notch: language server, built-in refactorings, type and typedoc information on hover, snappy go-to-definition | language server is a work in progress, some IDEs use the CLI and require saving the file to run the type-check, refactorings in alpha, only type information on hover, sketchy go-to-definition |\n| type-checking speed (excluding transpilation) | [benchmarks needed](https://github.com/niieani/typescript-vs-flowtype/edit/master/README.md) | [benchmarks needed](https://github.com/niieani/typescript-vs-flowtype/edit/master/README.md), [in-depth description \u003cimg width=\"439\" title=\"numberOfFiles · O( (LoCperFile + SizeOfTypesOfExports) ^ k )\" alt=\"numberOfFiles · O( (LoCperFile + SizeOfTypesOfExports) ^ k )\" src=\"https://user-images.githubusercontent.com/563469/31196357-c02ca3e4-a94d-11e7-9292-f92e10091ac7.png\"\u003e ](https://youtu.be/WgvAPzOmiP0?t=616) |\n| autocomplete | \u003cul\u003e\u003cli\u003eboth during declaration and usage\u003c/li\u003e\u003cli\u003efeels instantaneous\u003c/li\u003e\u003cli\u003efeels reliable\u003c/li\u003e\u003c/ul\u003e | \u003cul\u003e\u003cli\u003e[only for usage](https://github.com/facebook/flow/issues/3074)\u003c/li\u003e\u003cli\u003efeels sluggish (often a second or more of delay)\u003c/li\u003e\u003cli\u003efeels unreliable (sometimes does not show up at all)\u003c/li\u003e\u003c/ul\u003e |\n| expressiveness | great (since TS @ 2.1) | great |\n| type safety | very good (7 / 10) | great (8 / 10) |\n| specifying generic parameters during call-time (`f\u003cT\u003e(x)`) | yes [e.g.](http://www.typescriptlang.org/play/#src=function%20someFactory%3CT%3E()%20%7B%0D%0A%20%20return%20class%20%7B%0D%0A%20%20%20%20method(someParam%20%3A%20T)%20%7B%0D%0A%20%20%20%20%20%20%0D%0A%20%20%20%20%7D%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0A%2F%2F%20how%20to%20invoke%20this%20factory%20with%20a%20defined%20%3CT%3E%3F%0D%0A%0D%0Aconst%20SomeClass%20%3D%20someFactory%3C%7B%20whatever%3A%20string%20%7D%3E()%0D%0Aconst%20someInstance%20%3D%20new%20SomeClass()%0D%0AsomeInstance.method('will-error-here')%0D%0A) | yes (since Flow 0.72) |\n| specifying generic parameters for type definitions | yes | yes |\n| typings for public libraries | plenty of well maintained typings | a handful of mostly incomplete typings |\n| unique features | \u003cul\u003e\u003cli\u003eautocomplete for object construction\u003c/li\u003e\u003cli\u003edeclarable `this` in functions (typing `someFunction.bind()`)\u003c/li\u003e\u003cli\u003elarge library of typings\u003c/li\u003e\u003cli\u003emore flexible [type mapping via iteration](https://github.com/Microsoft/TypeScript/pull/12114)\u003c/li\u003e\u003cli\u003enamespacing\u003c/li\u003e\u003c/ul\u003e | \u003cul\u003e\u003cli\u003evariance\u003c/li\u003e\u003cli\u003eexistential types `*` (deprecated since 0.72)\u003c/li\u003e\u003cli\u003etesting potential code-paths when types not declared for maximum inference\u003c/li\u003e\u003cli\u003e`$Diff\u003cA, B\u003e` type\u003c/li\u003e\u003c/ul\u003e |\n| type spread operator | no ([planned](https://github.com/microsoft/TypeScript/issues/10727)) | [shipped](https://github.com/facebook/flow/commit/ad443dc92879ae21705d4c61b942ba2f8ad61e4d) \u003e=0.42 |\n| support for nullish coalescing proposal | [shipped](https://github.com/microsoft/TypeScript/pull/32883) \u003e 3.7beta | yes |\n| support for decorators proposal | yes, legacy proposal | only parsing of legacy proposal, no type-checking |\n| support for extending built-in types | yes | no |\n| userland plugins | [basic](https://github.com/Microsoft/TypeScript/issues/6508), not effecting emitting yet (planned) | no |\n| programmatic hooking | architecture prepared, work in progress | work in progress |\n| documentation and resources | \u003cul\u003e\u003cli\u003every good docs\u003c/li\u003e\u003cli\u003emany books\u003c/li\u003e\u003cli\u003evideos\u003c/li\u003e\u003cli\u003ee-learning resources\u003c/li\u003e\u003c/ul\u003e | \u003cul\u003e\u003cli\u003eincomplete, often vague docs\u003c/li\u003e\u003cul\u003e |\n| ease-of-understanding of errors | good | good in some, vague in other cases |\n| transparency | meeting notes, leadership reasoning and roadmap happens mostly publicly | low transparency, roadmap developed behind closed doors |\n| commercial support | no | no |\n| nominal and structural typing | [structural](https://www.typescriptlang.org/docs/handbook/type-compatibility.html) with [plans to support nominal](https://github.com/microsoft/TypeScript/pull/33038) | mostly [structural](https://flow.org/en/docs/lang/nominal-structural/), nominal for [classes](https://flow.org/en/docs/lang/nominal-structural/#toc-classes-are-nominally-typed) and [imported opaque type aliases](https://flow.org/en/docs/types/opaque-types/#toc-outside-the-defining-file) |\n| dynamic import types | `import('module-name')` since [2.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#import-types) | undocumented `$Exports\u003c'module-name'\u003e` |\n| utility size (*not* emitted JavaScript) (latest version) | [![typescript size](https://packagephobia.now.sh/badge?p=typescript)](https://packagephobia.now.sh/result?p=typescript) | [![flow-bin size](https://packagephobia.now.sh/badge?p=flow-bin)](https://packagephobia.now.sh/result?p=flow-bin) |\n\n# Differences in syntax\n\n## bounded polymorphism\n\n### Flow\n\n```js\nfunction fooGood\u003cT: { x: number }\u003e(obj: T): T {\n  console.log(Math.abs(obj.x));\n  return obj;\n}\n```\n\n### TypeScript\n\n```ts\nfunction fooGood\u003cT extends { x: number }\u003e(obj: T): T {\n  console.log(Math.abs(obj.x));\n  return obj;\n}\n```\n\n### Reference\n\nhttps://flow.org/blog/2015/03/12/Bounded-Polymorphism/\n\n## maybe \u0026 nullable type\n\n### Flow\n\n```js\nlet a: ?string\n\n// equivalent to:\n\nlet a: string | null | void\n```\n\n### TypeScript\n\n```ts\nlet a: string | null | undefined\n```\n\nOptional parameters [implicitly add `undefined`](https://github.com/Microsoft/TypeScript/issues/13195):\n\n```ts\nfunction f(x?: number) { }\n// is semantically the same as:\nfunction f(x: number | undefined) { }\n// and also same as (the `| undefined` is redundant):\nfunction f(x?: number | undefined) { }\n```\n\nOptional properties implicitly add `undefined`\n\n```ts\nclass A {\n  foo?: string;\n}\n```\n\n## type casting\n\n### Flow\n\n```js\n(1 + 1 : number);\n```\n\n### TypeScript\n\n```ts\n(1 + 1) as number;\n\n// OR (old version, not recommended):\n\n\u003cnumber\u003e (1 + 1);\n```\n\n## mapping dynamic module names\n\n### Flow\n\n`.flowconfig`\n\n```ini\n[options]\nmodule.name_mapper='^\\(.*\\)\\.css$' -\u003e '\u003cPROJECT_ROOT\u003e/CSSModule.js.flow'\n```\n\n`CSSModule.js.flow`\n\n```js\n// @flow\n\n// CSS modules have a `className` export which is a string\ndeclare export var className: string;\n```\n\n### TypeScript\n\n```ts\ndeclare module \"*.css\" {\n  export const className: string;\n}\n```\n\n### Reference\n\n- https://www.typescriptlang.org/docs/handbook/modules.html\n- https://flow.org/en/docs/types/modules/\n\n## Exact/Partial Object Types\n\nBy default objects in Flow are not exact, i.e. they can contain more properties than declared, whereas in TypeScript they are always exact (must contain only declared properties). In [future versions](https://medium.com/flow-type/on-the-roadmap-exact-objects-by-default-16b72933c5cf) Flow plans to change this and make objects exact by default.\n\n### Flow\n\nWhen using flow, `{ name: string }` only means “an object with **at least** a name property”.\n\n```js\ntype ExactUser = {| name: string, age: number |};\ntype User = { name: string, age: number };\ntype OptionalUser = $Shape\u003cUser\u003e; // all properties become optional\n```\n\n### TypeScript\n\nTypeScript is more strict here, in that if you want to use a property which is not declared, you must explicitly say so by defining the indexed property. It is possible to use [dotted syntax](https://github.com/Microsoft/TypeScript/pull/12671) to access indexed properties since TypeScript 2.2. This is mostly a design decision as it forces you to write the typings upfront.\n\n```js\ntype ExactUser = { name: string, age: number };\ntype User = { name: string, age: number, [otherProperty: string]: any };\ntype OptionalUser = Partial\u003cExactUser\u003e; // all properties become optional\n```\n\n### Reference\n\n- https://flow.org/en/docs/types/objects/\n- https://github.com/Microsoft/TypeScript/issues/2710\n\n## Importing types\n\n### Flow\n\n```js\nimport type {UserID, User} from \"./User.js\";\n// equivalent:\nimport {type UserID, type User} from \"./User.js\";\n```\n\n### TypeScript\n\nTypeScript does not treat Types in any special way when importing.\n\n```ts\nimport {UserID, User} from \"./User.js\";\n```\n\n## typeof\n\nWorks the same in both cases, however Flow has an additional syntax to directly import a `typeof`:\n\n### Flow\n\n```js\nimport typeof {jimiguitar as GuitarT} from \"./User\";\n\n// OR\n\nimport {typeof jimiguitar} from \"./User.js\";\ntype GuitarT = jimiguitar;\n\n// OR (below also works in TypeScript)\n\nimport {jimiguitar} from \"./User.js\";\ntype GuitarT = typeof jimiguitar;\n```\n\n### TypeScript\n\n```ts\nimport {jimiguitar} from \"./User\";\ntype GuitarT = typeof jimiguitar;\n```\n\n## Restrictive type\n\nWhen you don't know a type, commonly you would use `any` type. A restrictive type accepts anything, like `any` but in order to use that variable you must ensure values type by refining it.\n\n### Flow\n\n`mixed`\n\n```js\nfunction stringifyNum(num: number) {\n  // Do stuff\n}\n\nfunction stringify(value: mixed) {\n  if (typeof value === 'string') {\n    return '' + value; // Works!\n  }\n  if (typeof value === 'number') {\n    return stringifyNum(value); // Works!\n  }\n  return '';\n}\n```\n\nReference: https://flow.org/en/docs/types/mixed/\n\n### Typescript\n\n`unknown`\n\n```ts\nfunction stringifyNum(num: number) {\n  // Do stuff\n}\n\nfunction stringify(value: unknown) {\n  if (typeof value === 'string') {\n    return '' + value; // Works!\n  }\n  if (typeof value === 'number') {\n    return stringifyNum(value); // Works!\n  }\n  return '';\n}\n```\n\nReference: https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#new-unknown-top-type\n\n## Accessing the type of a Class\n\nClasses are typed, so you don't need to define an explicit type for them.\nIf you want to reference the type, you can do it the following way:\n\n### Flow\n\n```js\nclass Test {};\ntype TestType = typeof Test;\n\nconst instance = new Test();\ntype TestTypeFromInstance = Class\u003ctypeof instance\u003e;\n```\n\n### TypeScript\n\n```ts\nclass Test {};\ntype TestType = typeof Test;\n```\n\n## Nominal typing\n\nFlow treats classes as nominal types, whereas TypeScript treats them as\nstructural types.\n\n### Flow\n```js\nclass Foo {};\nclass Bar {};\n\nconst foo: Foo = new Bar();\n// Cannot assign `new Bar()` to `foo` because `Bar` [1] is incompatible with `Foo` [2].\n```\n\n### TypeScript\n```ts\nclass Foo {};\nclass Bar {};\n\nconst foo: Foo = new Bar();\n// No errors!\n```\n\nYou can work around this with tricks like the following\n(`declare` only works in TypeScript \u003e=3.7.0):\n```ts\nclass Foo {\n    declare private __nominal: void;\n};\nclass Bar {\n    declare private __nominal: void;\n};\n\nconst foo: Foo = new Bar();\n// Type 'Bar' is not assignable to type 'Foo'.\n// Types have separate declarations of a private property '__nominal'.(2322)\n```\n\n## Keys/Props Of Type\n\n### Flow\n\n```js\nvar props = {\n  foo: 1,\n  bar: 'two',\n  baz: 'three',\n}\n\ntype PropsType = typeof props;\ntype KeysOfProps = $Enum\u003cPropsType\u003e;\n\nfunction getProp\u003cT\u003e(key: KeysOfProps): T {\n  return props[key]\n}\n```\n\n### TypeScript\n\n```ts\nvar props = {\n  foo: 1,\n  bar: 'two',\n  baz: 'three',\n}\n\ntype PropsType = typeof props\ntype KeysOfProps = keyof PropsType;\n\nfunction getProp\u003cT\u003e(key: KeysOfProps): T {\n  return props[key]\n}\n```\n\n## Records\n\n### Flow\n\n```js\ntype $Record\u003cT, U\u003e = {[key: $Enum\u003cT\u003e]: U}\ntype SomeRecord = $Record\u003c{ a: number }, string\u003e\n```\n\n### TypeScript\n\n```ts\ntype SomeRecord = Record\u003c{ a: number }, string\u003e\n```\n\n## Lookup Types\n\n### Flow\n\n```js\ntype A = {\n  thing: string\n}\n\n// when the property is a string constant use $PropertyType (i.e. you know it when typing)\ntype lookedUpThing = $PropertyType\u003cA, 'thing'\u003e\n\n// when you want the property to be dynamic use $ElementType (since Flow 0.49)\nfunction getProperty\u003cT : Object, Key : string\u003e(obj: T, key: Key): $ElementType\u003cT, Key\u003e {\n    return obj[key];\n}\n```\n\nReference:\n- https://github.com/facebook/flow/pull/2952#issuecomment-308248000\n- https://github.com/facebook/flow/commit/968210c5887b5bdd47d17167300033d1e1077d1a\n- https://github.com/facebook/flow/issues/2464#issuecomment-308536540\n- [flow/try](https://flow.org/try/#0MYGwhgzhAEBKCmwD2AnAJgHgLLwLYCN4UIAuaAeXwCtEAXAPmgG8AoaaNMWsMnAoiAG4WbaMgB2EWigCuwWqgAUnbrzyFiASmaj2tABYBLCADoVYaAF4OXMMPYBfUaIDm8WhgDS8AJ5kpKIbiLvSKANZk3j6aZAAkAKIgePDitAAqPgAO8NjqAgA00FGMrOxl0CjuMiji0AbGZrYA2mEAuvbQTk4itFnw0GlGwVY67DzQ4jL8KPmi+P7SQS6zThJSYkiS0nIKKABiYIYg1fBkCMjoGINLjNbi8ADucIioaIpM4wCMDtoA9L-QIgoVDQFhrWgVM4vS7XYK3CaPZ4XN4fMifQrzaAAcgAZkgkFifsIWIoUCY3LRFFiwFiYtAAktNIJoP9AShgSgSWSKVSaXTJtMmVzye4qfhaWQBRomSyAUDUMKeVjxXSGcEZSIcTJxPJDJtoBSAArA7IoXpXMiUGjyQpRBaBOGKJDUMhpQoRIq+OkJJK4FLpPpXW2+Eq6CpVGrQZ1UFrtFjdRRGk1EXrvTanaDfQpY9MSiZTaVAA)\n\n### TypeScript\n\nArguably, it's a bit easier to type both cases in TS, since they follow the same pattern.\n\n```ts\ntype A = {\n  thing: string\n}\n\ntype lookedUpThing = A['thing']\n\n// and...\n\nfunction getProperty\u003cT, K extends keyof T\u003e(obj: T, key: K) {\n    return obj[key];  // Inferred type is T[K]\n}\n\nfunction setProperty\u003cT, K extends keyof T\u003e(obj: T, key: K, value: T[K]) {\n    obj[key] = value;\n}\n```\n\nReference:\n- https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html\n- https://github.com/facebook/flow/issues/2310\n\n## Type-narrowing functions\n\nThese are functions that return a boolean, performing some logic to assert that a given input parameter is of a certain type.\n\nThe implementations differ between Flow and TypeScript:\n\nIn TypeScript, it ensures the mapping between: `true` and `value is T`, versus in the case of Flow, it ensures the value is \"checked\" against the logic within the body of the function (i.e. things like `typeof`, `instanceof`, `value === undefined`).\n\nThis means you cannot tell Flow that the tested parameter is of an arbitrary type, which closes the door to complex cases, e.g.:\n- reusing logic from a different function\n- library definitions, where there is no body at all (it is possible to specify the body in the declaration, however you are still limited by the type of assertions you may specify)\n\n### Flow\n\n```js\nfunction isNil(value: mixed): boolean %checks {\n  return value == null;\n}\n\nconst thing = null;\n\nif (!isNil(thing)) {\n  const another = thing.something;\n}\n```\n\nReference:\n- [flow/try](https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVxhngEwIYDOAFsAJYEBypMYUArgHYDGALqXA6vc2x2OVRgAKAG54YdAKYAuMAFtSAD0k4AlLIBGcODEl4GYAKRMikpgGsCYAN6owYAE6SWdBwbETJYALzewDOhgYAG5UAF90Jg4CFjAWIlIGAHMff0CQ9FIoMCEAQgFqIXjEpNVVGzswKIYYsH04eMkHVOLkgDoCODlnBOTQiKA)\n\n#### Caveats\n\nThe current implementation in Flow is incomplete, which means you [cannot](https://github.com/facebook/flow/issues/4723#issuecomment-408412026) yet use `%checks` in class methods.\n\nExample showing the limitation in the respective playgrounds: [TypeScript](https://typescript-play.js.org/#code/C4TwDgpgBAEgrgWwIYDsoF4oG8BQV9QpIIQBcUAzsAE4CWKA5gDR4EVzVEnlV2MsBfHDgBmcFAGNgtAPZoIKdtQjxkKABT0wcYFHKoQASj1QtO0xViJU2VvmXAOaUJBkjTKbbvQ+oAchkAIwArCCk-OwJ8ADJo-y4IPw8PL0io2P8lBKT6FJ00ggyXCDc84AA6BIxfP156Bgio9Lji0rMKrOJoH0xamnqIoRwJOSooJGpqJBAAeRFVVAoAQRQAEwA5RECIaktMAG1IrATyPwBRABs5PyZKJy7TgFk4CgBrPwEWKIBGACYAZhYAF1hCNFLoJlNZvNrIoMONJtM5gtFCsNlsdhRyiJaBdgDt1AolCpYYZhAB6clQYAAC1olnplCQIggt22EiQL2gAHdoK8UDJudSaTtoBNoHILiAoDTYZYRcpSDhIUiYWoKPsAAxAypdClUgC0RuNUEpoNGullahm1E2CG21HhKuhKOWaztDo1kUeSFp2KuMmo6gK+B9fqmaxkCHUxgAVAioci5WiPZjyhcFAxaZEySCcLR3ITFBwSWp1FbUDbU9RDMZcPhKcLGYyKMzWVB2ZyKDy+QKhbTGTSkJZgDIO2KZbCO9KB5YwDJ6MBWBWUFWMdRdSQcAIoBALt3bA2qbOLFBxK2WWywl2e1B+YLhdAcXvVjLh9Sx9txoR19Om3OFxQYAlXwFc13tHZNwgbcgA) vs [Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQAXAngBwKagBIFcBbAQwDtQBeUAb0VDtBKIMwC5QBnZAJwEsSBzADS167PF0bM2nXgOEBfRIkh4SAY2Q9YZTCTFdM+YiQAUfdHmSg2pVAEproAKRqAFpjUBrdtRF0DyOJkaFiwkKDmlhTklADksABGAFYeyLF+9HQAZFmgsZKYsRFkkcgZmTl5+gVFfMUWZZkVuSGYYfWWAHQF0XEyfPzpTfSVre2lndVM2DF93APpiohq2pygRFxcRKgA8pBGpOwAgiQAJgByhAmYXD6UANoZVAVssQCicCSxghxB068AWTw7E8sXkwkyAEYAEwAZmEAF0lCs9FYNltdvtCIcKOtNts9gc9CcLlcbuxOpAeNBkDcTLp9IZsSQ7EoQKBkK4eD5uRwiJBMD9rmoiMDsPBsJ4SAgOe4DHjsNpoKhQK5mT45YLQAkogAxODwUCnWCYdhfKz8TBWHjIFiIdEErHGdj3AAMCO60zZYAAtH7-aAQMjVlY1cYdlxLgRrlxcQ7MUTjmcozGXRkAUROZS4LAuCZyvQM1mtmdYAQTA4AFR4jGE9UklPkzrQXT8TkZVlIxA8cL0vTiJnGExh0gRxtcOwOGh0dmc3m89j8rXC0XscWS6WGucaog+ZCwbXYIiq5nalXb0DoWB8Ron8ORslcT3MRDyUCYaBr3wzsAX3mqRcBSFDxV3XUApRlTlsCpD9TlVXcOQPa51gYR8z1lXkrxvO06BHEgx0fZ9MFfIA)\n\n### TypeScript\n\nType-narrowing functions are called type guard functions in TypeScript.\n\n```ts\nfunction isNil\u003cT\u003e(value: T | null): value is null {\n  return value == null;\n}\n\nconst thing: any = null;\n\nif (!isNil(thing)) {\n  const another = thing.something;\n}\n```\n\n## Getting the type of a function call return value\n\n### Flow\n\n`$Call` utility type:\n\n```js\ntype Fn1 = \u003cT\u003e(T) =\u003e T;\ntype E = $Call\u003cFn1, number\u003e;\n\ndeclare var e: E; // E is number\n(42: E); // OK\n```\n\nReference: https://github.com/facebook/flow/commit/ac7d9ac68acc555973d495f0a3f1f97758eeedb4\n\n### TypeScript\n\n`ReturnType` utility type:\n\n```ts\ntype fn1\u003cT\u003e = (a: T) =\u003e T;\n\ntype E = ReturnType\u003cfn1\u003cnumber\u003e\u003e;\n\nvar e: E; // E is number\n```\n\n## Mapped Types / Foreach Property\n\n### Flow\n\n```js\ntype InputType = { hello: string };\ntype MappedType = $ObjMap\u003cInputType, ()=\u003enumber\u003e;\n```\n\nReference:\n\n- https://gist.github.com/gabro/bb83ed574690645053b815da2082b937\n- https://twitter.com/andreypopp/status/782192355206135808\n\n### TypeScript\n\nA bit more flexibility here, as you have access to each individual key name and can combine with Lookup types and even do simple transformations.\n\n```ts\ntype InputType = { hello: string };\ntype MappedType = {\n  [P in keyof InputType]: number;\n};\n```\n\n## Function and method overloading\n\n### Flow\n\nIt is possible to declare multiple signatures for the same method (also called: overloading). This feature is undocumented, and only available in type declarations (`.js.flow` files or module statements), not inline/alongside your code.\n\n```js\ndeclare function add(x: string, y: string): string;\ndeclare function add(x: number, y: number): number;\n\ndeclare class Adder {\n  add(x: string, y: string): string;\n  add(x: number, y: number): number;\n}\n```\n\nHowever, it's possible to create function overloads inline for functions outside of classes, by using additional declarations.\n\n```js\ndeclare function add(x: string, y: string): string;\ndeclare function add(x: number, y: number): number;\nfunction add(x, y) {\n  return x + y;\n}\n\nadd(1, 1); // Ok\nadd(\"1\", \"1\"); // Ok\nadd(1, \"1\"); // Error\n```\n\nIt is also possible to create function overloads using callable property syntax, see the section [Object callable property](#object-callable-property).\n\n### TypeScript\n\nTypeScript supports both function and method overloading, in both: type definitions (`.d.ts`) and inline alongside code.\n\n```ts\nclass Adder {\n  add(x: string, y: string): string;\n  add(x: number, y: number): number;\n  add(x, y) {\n    return x + y;\n  }\n}\n\n\nfunction add(x: string, y: string): string;\nfunction add(x: number, y: number): number;\nfunction add(x, y) {\n  return x + y;\n}\n```\n\n## Read-only Types\n\n### Flow\n\n```js\ntype A = {\n  +b: string\n}\n\nlet a: A = { b: 'something' }\na.b = 'something-else'; // ERROR\n```\n\n### TypeScript\n\n```ts\ntype A = {\n  readonly b: string\n}\n\nlet a: A = { b: 'something' }\na.b = 'something-else'; // ERROR\n```\n\nOne caveat that makes TypeScript's `readonly` less safe is that the same `non-readonly` property in a type is compatible with a `readonly` property. This essentially means that you can pass an object with `readonly` properties to a function which expects non-readonly properties and TypeScript will *not* throw errors: [example](https://www.typescriptlang.org/play/index.html#src=%0D%0Afunction%20test(x%3A%20%7B%20foo%3A%20string%20%7D)%20%7B%20%0D%0A%20%20%20%20x.foo%20%3D%20'bar'%3B%0D%0A%7D%0D%0A%0D%0Aconst%20x%3A%20%7B%20readonly%20foo%3A%20string%20%7D%20%3D%20%7B%20foo%3A%20'baz'%20%7D%3B%0D%0A%0D%0Atest(x)%3B).\n\n## \"Impossible flow\" type\n\n### Flow\n\n`empty`\n\n```js\nfunction returnsImpossible() {\n  throw new Error();\n}\n\n// type of returnsImpossible() is 'empty'\n```\n\n### TypeScript\n\n`never`\n\n```ts\nfunction returnsImpossible() {\n  throw new Error();\n}\n\n// type of returnsImpossible() is 'never'\n```\n\n## Difference types\n\n### Flow\n\n```js\ntype C = $Diff\u003c{ a: string, b: number }, { a: string }\u003e\n// C is { b: number}\n```\n\n\u003e It only works properly as lower bound, i.e. you can assign something to it, but can't use it after that.\n\n([source](https://github.com/facebook/flow/issues/3541#issuecomment-289291932))\n\nFlow also has `$Rest\u003c\u003e`, which represents the result of the JS object rest operator (`{ ...rest }`).\n\n```js\ntype Props = { name: string, age: number };\n\nconst props: Props = {name: 'Jon', age: 42};\nconst {age, ...otherProps} = props;\n(otherProps: $Rest\u003cProps, {|age: number|}\u003e);\notherProps.age;  // Error, since we removed it\n```\n\n### Typescript\n\nYou can define your own filter type, but it does not have a helper type for that.\n\n```ts\nclass A {\n  a: string;\n  b: number;\n}\n\nclass B {\n  a: string;\n  c: boolean;\n}\n\ntype Omit\u003cT, U\u003e = Pick\u003cT, Exclude\u003ckeyof T, keyof U\u003e\u003e;\n//  \n\ntype C = Omit\u003cA, B\u003e;\n// C is { b: number }\n```\n\nHowever, Flow implementation is stricter in this case, as B have a property that A does not have, it would rise an error. In Typescript, however, they would be ignored.\n\n# Same syntax\n\nMost of the syntax of Flow and TypeScript is the same. TypeScript is more expressive for certain use-cases (advanced mapped types with keysof, readonly properties), and Flow is more expressive for others (e.g. `$Diff`).\n\n## Object callable property\n\nThe basic syntax are the same, except Flow has special syntax for the internal call property slot.\n\nBoth can be used to annotate function statics.\n\n### Flow\n\nYou can use objects with callable properties as functions: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AMVALygDeiooAFAJQBcoAzigE4CWAdgOaIC+A3IgGNYbRqEh18RaoQB8oAEQALLNDjz+QkSlDLVsOo1adCY6ryA)\n\n```js\ntype F = {\n  (): string\n};\nconst f: F = () =\u003e \"hello\";\nconst hello: string = f();\n```\n\nAn overloaded function is a function with multiple call signatures.\nThis is supported by Flow. And we list out the different syntaxes here: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AMVALygDeiooAFAJQBcoAzigE4CWAdgOYA0ZoA2nwDGAQ2jQAuuLoU2AVwC2AIyxMqhAHwNm7brwEixkio1adaW0x0QBfZINhtGoSHXxEKADwD8dOUpWgAD4WOmoEmqTkTFgoskxsoB6gXokAdCiwAMranNSgdADkBQDcNohAA)\n\n```js\ntype F = {\n  (): string,\n  [[call]]: (number) =\u003e string,\n  [[call]](string): string\n}\n\nconst f: F = (x?: number | string) =\u003e {\n  return x ? x.toString() : '';\n}\n```\n\nUse call property to annotate function statics: [Try Flow](https://flow.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AWSwLawCWAXlgCYBiAhgMYqwBOxN0AKpjgLygDeiUKDr0AFlgBc-QaACQAbQB2AVwIAjLEwC6Ules0yAvgBoZ8+SOjQtWgBR6NTAJS7Vj04eR1YigM4pQSHpGFjYpfCIySloGZlYOLlBeRSSAPmkhYkhQWwBCINjQ6AA6ETpxJwyhQOC4tlKxHn5PIRbQLJyCkPiG8qwlLVBc7l5lRQosSGJFSkqBatAmLBRlJhSuupKy8QGjGQ2i3p3FQeSkkdAABlAAflAARlBdUAAqGsL4+1AAWgenGSWKzW7269W2-ROiEMQA)\n\n```js\ntype MemoizedFactorialType = {\n  cache: {\n    [number]: number,\n  },\n  [[call]](number): number,\n}\n\nconst factorial: MemoizedFactorialType = n =\u003e {\n  if (!factorial.cache) {\n    factorial.cache = {}\n  }\n  if (factorial.cache[n] !== undefined) {\n    return factorial.cache[n]\n  }\n  factorial.cache[n] = n === 0 ? 1 : n * factorial(n - 1)\n  return factorial.cache[n]\n}\n```\n\nReference:\n\n- [Callable Objects](https://flow.org/en/docs/types/functions/#callable-objects-)\n- [immer.js](https://github.com/immerjs/immer/blob/master/src/immer.js.flow) uses it to overload the `produce` (default export) function which has multiple call signatures\n- [Styled Components](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/styled-components_v4.x.x/flow_v0.75.x-/styled-components_v4.x.x.js#L242) uses it to separate cases of being called on a string and wrapping a component\n- [Reselect Library Definition](https://github.com/flow-typed/flow-typed/blob/master/definitions/npm/re-reselect_v2.x.x/flow_v0.67.1-/re-reselect_v2.x.x.js) contains massive chunks of overloaded call properties\n\n### TypeScript\n\nYou can use objects with callable properties as functions: [TypeScript Playground](https://www.typescriptlang.org/play/#src=type%20F%20%3D%20%7B%0D%0A%20%20()%3A%20string%3B%0D%0A%7D%0D%0Aconst%20foo%3A%20F%20%3D%20()%20%3D%3E%20%22hello%22%3B%0D%0Aconst%20bar%3A%20string%20%3D%20foo()%3B)\n\n```ts\ntype F = {\n  (): string;\n}\nconst foo: F = () =\u003e \"hello\";\nconst bar: string = foo();\n```\n\nAn overloaded function is a function with multiple call signatures.\nThis is also supported by TypeScript: [TypeScript Playground](https://www.typescriptlang.org/play/#src=type%20F%20%3D%20%7B%0D%0A%20%20()%3A%20string%2C%0D%0A%20%20(number)%3A%20string%2C%0D%0A%20%20(string)%3A%20string%0D%0A%7D%0D%0A%0D%0Aconst%20f%3A%20F%20%3D%20(x%3F%3A%20number%20%7C%20string)%20%3D%3E%20%7B%0D%0A%20%20return%20x%20%3F%20x.toString()%20%3A%20''%3B%0D%0A%7D%0D%0A)\n\n\n```ts\ntype F = {\n  (): string,\n  (x: number): string,\n  (x: string): string\n}\n\nconst f: F = (x?: number | string) =\u003e {\n  return x ? x.toString() : '';\n}\n```\n\nUse call property to annotate function statics: [TypeScript Playground](https://www.typescriptlang.org/play/#src=type%20MemoizedFactorialType%20%3D%20%7B%0D%0A%20%20cache%3F%3A%20%7B%0D%0A%20%20%20%20%5Bn%3A%20number%5D%3A%20number%2C%0D%0A%20%20%7D%2C%0D%0A%20%20(n%3A%20number)%3A%20number%2C%0D%0A%7D%0D%0A%0D%0Aconst%20factorial%3A%20MemoizedFactorialType%20%3D%20n%20%3D%3E%20%7B%0D%0A%20%20if%20(!factorial.cache)%20%7B%0D%0A%20%20%20%20factorial.cache%20%3D%20%7B%7D%0D%0A%20%20%7D%0D%0A%20%20else%20if%20(factorial.cache%5Bn%5D%20!%3D%3D%20undefined)%20%7B%0D%0A%20%20%20%20return%20factorial.cache%5Bn%5D%0D%0A%20%20%7D%0D%0A%20%20factorial.cache%5Bn%5D%20%3D%20n%20%3D%3D%3D%200%20%3F%201%20%3A%20n%20*%20factorial(n%20-%201)%0D%0A%20%20return%20factorial.cache%5Bn%5D%0D%0A%7D)\n\n```ts\ntype MemoizedFactorialType = {\n  cache?: {\n    [n: number]: number,\n  },\n  (n: number): number,\n}\n\nconst factorial: MemoizedFactorialType = n =\u003e {\n  if (!factorial.cache) {\n    factorial.cache = {}\n  }\n  else if (factorial.cache[n] !== undefined) {\n    return factorial.cache[n]\n  }\n  factorial.cache[n] = n === 0 ? 1 : n * factorial(n - 1)\n  return factorial.cache[n]\n}\n```\n\nReference:\n- [Callable on TypeScript Book](https://github.com/basarat/typescript-book/blob/master/docs/types/callable.md)\n\n\n## optional parameters\n\n### Flow and TypeScript\n\nThe syntax in either tool is the same - question mark: `?` suffixing the parameter name:\n\n```js\nfunction(a?: string) {}\n```\n\n## call-time generic parameters\n\nIn TypeScript and Flow (since version 0.72) you may use specify\nthe type of a generic when calling the generic function or the constructor.\n\n```ts\nconst set = new Set\u003cstring\u003e();\n```\n\nOr using a more complex behavior:\n\n```ts\nfunction makeTgenerator\u003cT\u003e() {\n  return function(next: () =\u003e T) {\n    const something = next();\n    return something;\n  }\n}\n\nconst usage = makeTgenerator\u003cstring\u003e()\n// 'usage' is of type: (next: () =\u003e string) =\u003e string\n```\n\n## Typing pure JS files (i.e. without transpilation)\n\n### Flow\n\nFlow supports a comment-based syntax, by encapsulating type annotations in `/* */`-style comments:\n\n```js\nconst f = (x /*: number */, y /*: number */) /*: number */ =\u003e x + y\n```\n\n### TypeScript\n\nTypeScript can check types with JavaScript files annotated with JSDoc comments:\n\n```js\n// JSDoc type syntax\n/** @type {function(number, number): number} */\nconst f = (x, y) =\u003e x + y\n// equivalent TypeScript type syntax\n/** @type {(x: number, y: number) =\u003e number} */\n```\n\nJSDoc's overloaded function comment syntax is not supported:\n\n```js\n/**\n * @param {string} input\n * @returns {string} result\n *//**\n * @param {number} input\n * @returns {string} result\n */\nfunction notSupported(input) { /* omit */ }\n```\n\nHowever, we can express [function overloading type in TypeScript's form][spec] in a tricky way:\n\n```js\n/** @type {{\n            (): void;\n            (code: 0): void;\n            (code: 1, msg: string): void\n          }} */\nconst functionOverloads = (\n  /** @type {0 | 1} */ code = 0,\n  /** @type {string | undefined} */ msg = code === 0 ? undefined : \"\"\n) =\u003e { /* omit */ }\n```\n\n[spec]: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#62-function-overloads\n\nHowever, it still lacks some features:\n\n1. There is no way to pass type parameter when invoking generic functions.\n2. TypeScript cannot parse conditional types in JSDoc comments correctly. [#27424]\n3. There is no equivalent form of `as const` assertion. [#30445]\n\n[#27424]: https://github.com/microsoft/TypeScript/issues/27424\n[#30445]: https://github.com/Microsoft/TypeScript/issues/30445\n\n# TypeScript-only concepts\n\n## Declarable arbitrary `this` in functions (outside of objects)\n\n```ts\nfunction something(this: { hello: string }, firstArg: string) {\n  return this.hello + firstArg;\n}\n```\n\n## Private and Public properties in classes\n\n```ts\nclass SomeClass {\n  constructor(public prop: string, private prop2: string) {\n    // transpiles to:\n    // this.prop = prop;\n    // this.prop2 = prop2;\n  }\n  private prop3: string;\n}\n```\n\n## [Non-null assertion operator](https://github.com/Microsoft/TypeScript/pull/7140)\n\nAdd `!` to signify we know an object is non-null.\n\n```ts\n// Compiled with --strictNullChecks\nfunction validateEntity(e?: Entity) {\n  // Throw exception if e is null or invalid entity\n}\n\nfunction processEntity(e?: Entity) {\n  validateEntity(e);\n  let s = e!.name;  // Assert that e is non-null and access name\n}\n```\n\n## Conditional Typing\n\n```ts\ntype XorY\u003cT, U\u003e = T extends U ? X : Y;\n```\n\nThis alone, introduces new helper types, or types aliases.\n\n```ts\ntype Exclude\u003cT, U\u003e = T extends U ? never : T;\n\n/**\n * Extract from T those types that are assignable to U\n */\ntype Extract\u003cT, U\u003e = T extends U ? T : never;\n\n/**\n * Exclude null and undefined from T\n */\ntype NonNullable\u003cT\u003e = T extends null | undefined ? never : T;\n\n/**\n * Obtain the return type of a function type\n */\ntype ReturnType\u003cT extends (...args: any[]) =\u003e any\u003e =\n    T extends (...args: any[]) =\u003e infer R ? R : any;\n```\n\n## Mapped Type Modifiers\n\nYou can use `+` and `-` operators to modify mapped types.\n\n```ts\ntype Mutable\u003cT\u003e = {\n  -readonly [P in keyof T]: T[P]\n}\n\ninterface Foo {\n  readonly abc: number;\n}\n\n// 'abc' is no longer read-only.\ntype TotallyMutableFoo = Mutable\u003cFoo\u003e\n```\n\n### Helper type modifiers\n\n`Required` is a type mapper to make all properties of an object to be required.\n\n`Partial` is a type mapper to make all properties of an object to be optional.\n\n`Readonly` is a type mapper to make all properties of an object to be readonly.\n\n# Flow-only concepts\n\n## Inferred existential types\n\n`*` as a type or a generic parameter signifies to the type-checker to infer the type if possible\n\n```js\nArray\u003c*\u003e\n```\n\nHowever this type was deprecated in [Flow 0.72](https://github.com/facebook/flow/blob/master/Changelog.md#0720).\n\n[TypeScript proposal](https://github.com/Microsoft/TypeScript/pull/26349)\n\n## Variance\n\nhttps://flow.org/en/docs/lang/variance/\n\n```js\nfunction getLength(o: {+p: ?string}): number {\n  return o.p ? o.p.length : 0;\n}\n```\n\n[TypeScript proposal](https://github.com/Microsoft/TypeScript/issues/10717)\n\nBivariance is among [the design decisions](https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-function-parameters-bivariant) driving TypeScript.\n\n## Opaque Type Alias \n\nhttps://flow.org/en/docs/types/opaque-types/\n\n```js\nopaque type Alias = Type;\nopaque type Alias: SuperType = Type; // with subtyping constrains\n```\n\nWithin the same file the opaque type alias is defined, opaque type aliases behave exactly as type aliases.\n\nOutside the defining file, i.e. when importing an opaque type alias, it behaves like a nominal type.\nIf the opaque type alias is defined with subtyping constrains, it can be used as the super type when outside the defining file.\n\n```js\nexport opaque type Age: number = number;\n\nfunction newAge(age: number): Age {\n    return age; // ok within same file, not ok outside defining file\n}\n\nfunction incAge(age: Age): number {\n    return age + 1; // ok\n}\n```\n\nTypeScript dose not have opaque type, but we can define an utility type with intersection type\nto mimic the behavior of Flow's opaque type alias with subtyping constrains used outside the defining file.\n\n```ts\ntype Opaque\u003cT, U\u003e = U \u0026 { readonly __TYPE__: T }\ntype Age = Opaque\u003c'age', number\u003e\n\nfunction newAge(age: number): Age {\n    return age; // not ok\n}\n\nfunction incAge(age: Age): number {\n    return age + 1; // ok\n}\n```\n\n## Object type spread\n\nObject type spread acts as [object spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) but for types. Unlike [intersection types](https://flow.org/en/docs/types/intersections/) type spreads work with exact object types and overwrite existing properties.\n\n```js\ntype Foo = {| foo: string, bar: string |}\ntype Bar = {| bar: number |}\n\ntype FooBarIntersection = Foo \u0026 Bar\ntype FooBarSpread = {| ...Foo, ...Bar |}\n\nconst fooBarInterect: FooBarIntersection = { foo: '123', bar: 12 } // not ok\nconst fooBarString: FooBarSpread = { foo: '123', bar: 'string' } // not ok\nconst fooBar: FooBarSpread = { foo: '123', bar: 12 } // ok\n```\n\nWhile TypeScript does understand object spread, the support for object type spread is [not implemented](https://github.com/microsoft/TypeScript/issues/10727).\n\n## Useful References\n\n* https://github.com/Microsoft/TypeScript/issues/1265\n* Undocumented Flow modifiers https://github.com/facebook/flow/issues/2464\n* http://sitr.us/2015/05/31/advanced-features-in-flow.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniieani%2Ftypescript-vs-flowtype","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniieani%2Ftypescript-vs-flowtype","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniieani%2Ftypescript-vs-flowtype/lists"}