Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Differences between Flowtype and TypeScript -- syntax and usability

License

NotificationsYou must be signed in to change notification settings

Bjeaurn/typescript-vs-flowtype

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

63 Commits
 
 
 
 

Repository files navigation

Both TypeScript and Flow are very similar products and they share most of their syntax with some important differences.In this document I've tried to compile the list of differences and similarities between Flowtype and TypeScript -- specifically the syntax, usage and usability.

Disclaimer

This document might be incomplete and/or contain mistakes and was last updated to describeTypeScript 3.2 andFlow 0.86.

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 andediting this page.

Thanks!

Differences in usage and usability

Some of these differences are subjective (e.g. error readability), and I'd love to make this as scientific as possible — so pleasecontribute to make it better. :)

TypeScriptFlow
Leading Design Goal / North Staridentify errors in programs througha balance between correctness and productivityenforce type soundness / safety
IDE integrationstop-notch: language server, built-in refactorings, type and typedoc information on hover, snappy go-to-definitionlanguage 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
type-checking speed (excluding transpilation)benchmarks neededbenchmarks needed,in-depth descriptionnumberOfFiles · O( (LoCperFile + SizeOfTypesOfExports) ^ k )
autocomplete
  • both during declaration and usage
  • feels instantaneous
  • feels reliable
  • only for usage
  • feels sluggish (often a second or more of delay)
  • feels unreliable (sometimes does not show up at all)
expressivenessgreat (since TS @ 2.1)great
type safetyvery good (7 / 10)great (8 / 10)
specifying generic parameters during call-time (f<T>(x))yese.g.yes (since Flow 0.72)
specifying generic parameters for type definitionsyesyes
typings for public librariesplenty of well maintained typingsa handful of mostly incomplete typings
unique features
  • autocomplete for object construction
  • declarablethis in functions (typingsomeFunction.bind())
  • large library of typings
  • more flexibletype mapping via iteration
  • namespacing
  • variance
  • existential types* (deprecated since 0.72)
  • testing potential code-paths when types not declared for maximum inference
  • $Diff<A, B> type
  • Predicate function%checks, which will instruct the compiler on the non-nullable state of a variable
type spread operatorshipped > 3.2rcshipped >=0.42
support for nullish coalescing proposalnoyes
support for decorators proposalyes, legacy proposalonly parsing of legacy proposal, no type-checking
support for extending built-in typesyesno
userland pluginsbasic, not effecting emitting yet (planned)no
programmatic hookingarchitecture prepared, work in progresswork in progress
documentation and resources
  • very good docs
  • many books
  • videos
  • e-learning resources
  • incomplete, often vague docs
    ease-of-understanding of errorsgoodgood in some, vague in other cases
    transparencymeeting notes, leadership reasoning and roadmap happens mostly publiclylow transparency, roadmap developed behind closed doors
    commercial supportnono
    nominal and structural typingstructuralmostlystructural, nominal forclasses andimported opaque type aliases
    utility size (not emitted JavaScript) (latest version)typescript sizeflow-bin size

    Differences in syntax

    bounded polymorphism

    Flow

    functionfooGood<T:{x:number}>(obj: T): T{console.log(Math.abs(obj.x));returnobj;}

    TypeScript

    functionfooGood<Textends{x:number}>(obj:T):T{console.log(Math.abs(obj.x));returnobj;}

    Reference

    https://flow.org/blog/2015/03/12/Bounded-Polymorphism/

    maybe & nullable type

    Flow

    leta: ?string// equivalent to:leta:string|null|void

    TypeScript

    leta:string|null|undefined

    Optional parametersimplicitly addundefined:

    functionf(x?:number){}// is semantically the same as:functionf(x:number|undefined){}// and also same as (the `| undefined` is redundant):functionf(x?:number|undefined){}

    Optional properties implicitly addundefined

    classA{foo?:string;}

    type casting

    Flow

    (1+1 :number);

    TypeScript

    (1+1)asnumber;// OR (old version, not recommended):<number>(1+1);

    mapping dynamic module names

    Flow

    .flowconfig

    [options]module.name_mapper='^\(.*\)\.css$' ->'<PROJECT_ROOT>/CSSModule.js.flow'

    CSSModule.js.flow

    //@flow// CSS modules have a `className` export which is a stringdeclareexportvarclassName:string;

    TypeScript

    declare module"*.css"{exportconstclassName:string;}

    Reference

    Exact/Partial Object Types

    By 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). Infuture versions Flow plans to change this and make objects exact by default.

    Flow

    When using flow,{ name: string } only means “an object withat least a name property”.

    typeExactUser={|name:string,age:number|};typeUser={name:string,age:number};typeOptionalUser=$Shape<User>;// all properties become optional

    TypeScript

    TypeScript 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 usedotted syntax to access indexed properties since TypeScript 2.2. This is mostly a design decision as it forces you to write the typings upfront.

    typeExactUser={name:string,age:number};typeUser={name:string,age:number,[otherProperty:string]:any};typeOptionalUser=Partial<ExactUser>;// all properties become optional

    Reference

    Importing types

    Flow

    importtype{UserID,User}from"./User.js";// equivalent:import{typeUserID,typeUser}from"./User.js";

    TypeScript

    TypeScript does not treat Types in any special way when importing.

    import{UserID,User}from"./User.js";

    typeof

    Works the same in both cases, however Flow has an additional syntax to directly import atypeof:

    Flow

    importtypeof{jimiguitarasGuitarT}from"./User";// ORimport{typeofjimiguitar}from"./User.js";typeGuitarT=jimiguitar;// OR (below also works in TypeScript)import{jimiguitar}from"./User.js";typeGuitarT=typeofjimiguitar;

    TypeScript

    import{jimiguitar}from"./User";typeGuitarT=typeofjimiguitar;

    Restrictive type

    When you don't know a type, commonly you would useany type. A restrictive type accepts anything, likeany but in order to use that variable you must ensure values type by refining it.

    Flow

    mixed

    functionstringifyNum(num:number){// Do stuff}functionstringify(value:mixed){if(typeofvalue==='string'){return''+value;// Works!}if(typeofvalue==='number'){returnstringifyNum(value);// Works!}return'';}

    Reference:https://flow.org/en/docs/types/mixed/

    Typescript

    unknown

    functionstringifyNum(num:number){// Do stuff}functionstringify(value:unknown){if(typeofvalue==='string'){return''+value;// Works!}if(typeofvalue==='number'){returnstringifyNum(value);// Works!}return'';}

    Reference:https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#new-unknown-top-type

    Accessing the type of a Class

    Classes are typed, so you don't need to define an explicit type for them.If you want to reference the type, you can do it the following way:

    Flow

    classTest{};typeTestType=typeofTest;constinstance=newTest();typeTestTypeFromInstance=Class<typeofinstance>;

    TypeScript

    classTest{};typeTestType=typeofTest;

    Keys/Props Of Type

    Flow

    varprops={foo:1,bar:'two',baz:'three',}typePropsType=typeofprops;typeKeysOfProps=$Enum<PropsType>;functiongetProp<T>(key: KeysOfProps): T{returnprops[key]}

    TypeScript

    varprops={foo:1,bar:'two',baz:'three',}typePropsType=typeofpropstypeKeysOfProps=keyofPropsType;functiongetProp<T>(key:KeysOfProps):T{returnprops[key]}

    Records

    Flow

    type$Record<T,U>={[key:$Enum<T>]:U}typeSomeRecord=$Record<{a:number},string>

    TypeScript

    typeSomeRecord=Record<{a:number},string>

    Lookup Types

    Flow

    typeA={thing:string}// when the property is a string constant use $PropertyType (i.e. you know it when typing)typelookedUpThing=$PropertyType<A,'thing'>// when you want the property to be dynamic use $ElementType (since Flow 0.49)functiongetProperty<T :Object,Key :string>(obj: T, key: Key): $ElementType<T,Key>{returnobj[key];}

    Reference:

    TypeScript

    Arguably, it's a bit easier to type both cases in TS, since they follow the same pattern.

    typeA={thing:string}typelookedUpThing=A['thing']// and...functiongetProperty<T,KextendskeyofT>(obj:T,key:K){returnobj[key];// Inferred type is T[K]}functionsetProperty<T,KextendskeyofT>(obj:T,key:K,value:T[K]){obj[key]=value;}

    Reference:

    Type-narrowing functions

    Flow

    Note: undocumented syntax, may change:

    functionisNil(value:mixed):boolean%checks{returnvalue==null;}constthing=null;if(!isNil(thing)){constanother=thing.something;}

    Reference:

    TypeScript

    Type-narrowing functions are called type guard functions in TypeScript.

    functionisNil<T>(value:T|null):value isnull{returnvalue==null;}constthing:any=null;if(!isNil(thing)){constanother=thing.something;}

    Getting the type of a function call return value

    Flow

    $Call utility type:

    typeFn1=<T>(T) =>T;typeE=$Call<Fn1,number>;declarevar e:E;// E is number(42:E);// OK

    Reference:https://github.com/facebook/flow/commit/ac7d9ac68acc555973d495f0a3f1f97758eeedb4

    TypeScript

    ReturnType utility type:

    typefn1<T>=(a:T)=>T;typeE=ReturnType<fn1<number>>;vare:E;// E is number

    Mapped Types / Foreach Property

    Flow

    typeInputType={hello:string};typeMappedType=$ObjMap<InputType,()=>number>;

    Reference:

    TypeScript

    A bit more flexibility here, as you have access to each individual key name and can combine with Lookup types and even do simple transformations.

    typeInputType={hello:string};typeMappedType={[PinkeyofInputType]:number;};

    Function and method overloading

    Flow

    It 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.

    declarefunctionadd(x:string,y:string):string;declarefunctionadd(x:number,y:number):number;declareclassAdder{add(x:string,y:string):string;add(x:number,y:number):number;}

    However, it's possible to create function overloads inline for functions outside of classes, by using additional declarations.

    declarefunctionadd(x:string,y:string):string;declarefunctionadd(x:number,y:number):number;functionadd(x,y){returnx+y;}add(1,1);// Okadd("1","1");// Okadd(1,"1");// Error

    TypeScript

    TypeScript supports both function and method overloading, in both: type definitions (.d.ts) and inline alongside code.

    classAdder{add(x:string,y:string):string;add(x:number,y:number):number;add(x,y){returnx+y;}}functionadd(x:string,y:string):string;functionadd(x:number,y:number):number;functionadd(x,y){returnx+y;}

    Read-only Types

    Flow

    typeA={+b:string}leta:A={b:'something'}a.b='something-else';// ERROR

    TypeScript

    typeA={readonlyb:string}leta:A={b:'something'}a.b='something-else';// ERROR

    One caveat that makes TypeScript'sreadonly less safe is that the samenon-readonly property in a type is compatible with areadonly property. This essentially means that you can pass an object withreadonly properties to a function which expects non-readonly properties and TypeScript willnot throw errors:example.

    "Impossible flow" type

    Flow

    empty

    functionreturnsImpossible(){thrownewError();}// type of returnsImpossible() is 'empty'

    TypeScript

    never

    functionreturnsImpossible(){thrownewError();}// type of returnsImpossible() is 'never'

    Difference types

    Flow

    typeC=$Diff<{a:string,b:number},{a:string}>// C is { b: number}

    Note however that $Diff is not an official feature.

    It only works properly as lower bound, i.e. you can assign something to it, but can't use it after that.

    (source)

    Typescript

    You can define your own filter type, but it does not have a helper type for that.

    classA{a:string;b:number;}classB{a:string;c:boolean;}typeOmit<T,U>=Pick<T,Exclude<keyofT,keyofU>>;//typeC=Omit<A,B>;// C is { b: number }

    However, 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.

    Same syntax

    Most 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).

    optional parameters

    Flow and TypeScript

    The syntax in either tool is the same - question mark:? suffixing the parameter name:

    function(a?:string){}

    call-time generic parameters

    In TypeScript and Flow (since version 0.72) you may use specifythe type of a generic when calling the generic function or the constructor.

    constset=newSet<string>();

    Or using a more complex behavior:

    functionmakeTgenerator<T>(){returnfunction(next:()=>T){constsomething=next();returnsomething;}}constusage=makeTgenerator<string>()// 'usage' is of type: (next: () => string) => string

    TypeScript-only concepts

    Declarable arbitrarythis in functions (outside of objects)

    functionsomething(this:{hello:string},firstArg:string){returnthis.hello+firstArg;}

    Private and Public properties in classes

    classSomeClass{constructor(publicprop:string,privateprop2:string){// transpiles to:// this.prop = prop;// this.prop2 = prop2;}privateprop3:string;}

    Add! to signify we know an object is non-null.

    // Compiled with --strictNullChecksfunctionvalidateEntity(e?:Entity){// Throw exception if e is null or invalid entity}functionprocessEntity(e?:Entity){validateEntity(e);lets=e!.name;// Assert that e is non-null and access name}

    Conditional Typing

    typeXorY<T,U>=TextendsU ?X :Y;

    This alone, introduces new helper types, or types aliases.

    typeExclude<T,U>=TextendsU ?never :T;/** * Extract from T those types that are assignable to U */typeExtract<T,U>=TextendsU ?T :never;/** * Exclude null and undefined from T */typeNonNullable<T>=Textendsnull|undefined ?never :T;/** * Obtain the return type of a function type */typeReturnType<Textends(...args:any[])=>any>=Textends(...args:any[])=> inferR ?R :any;

    Mapped Type Modifiers

    You can use+ and- operators to modify mapped types.

    typeMutable<T>={-readonly[PinkeyofT]:T[P]}interfaceFoo{readonlyabc:number;}// 'abc' is no longer read-only.typeTotallyMutableFoo=Mutable<Foo>

    Helper type modifiers

    Required is a type mapper to make all properties of an object to be required.

    Partial is a type mapper to make all properties of an object to be optional.

    Readonly is a type mapper to make all properties of an object to be readonly.

    Flow-only concepts

    Inferred existential types

    * as a type or a generic parameter signifies to the type-checker to infer the type if possible

    Array<*>

    However this type was deprecated inFlow 0.72.

    TypeScript proposal

    Variance

    https://flow.org/en/docs/lang/variance/

    functiongetLength(o:{+p: ?string}):number{returno.p ?o.p.length :0;}

    TypeScript proposal

    Bivariance is amongthe design decisions driving TypeScript.

    Useful References

    About

    Differences between Flowtype and TypeScript -- syntax and usability

    Resources

    License

    Stars

    Watchers

    Forks

    Releases

    No releases published

    Packages

    No packages published

    [8]ページ先頭

    ©2009-2025 Movatter.jp