Skip to content

Latest commit

 

History

History
73 lines (71 loc) · 18.6 KB

syntax-comparison.md

File metadata and controls

73 lines (71 loc) · 18.6 KB

JavaScript Type System Syntax Comparison

The table included below compares the syntax used for various type system constructs and other applications of types such as type annotation sites.

Feature TypeScript syntax Flow syntax Hegel syntax Closure compiler (in comments) Notes
Arrays T[] Array<T> Flow also supports T[] but wants to deprecate it
Tuple type [S, T, ...] Same as TS
Annotating function parameter function f(x: S) {} Same as TS Same as TS @param {S} x
Annotating return value function f() : S {} Same as TS Same as TS @return {S}
Annotating rest parameters function f(...x : S[]) function f(...x : Array<S>) Same as Flow @param {...S} x Flow also accepts the TS annotation.
Variable annotation let x:S = foo; Same as TS Same as TS @type {S}
Function type (x: S, ...) => T (S, ...) => T Same as Flow function(S, T, ...): U In TS, parameter names are required and types can be omitted (defaults to any). In Flow, they are optional.
Function type with rest parameter (...x : S[]) => T (...x : Array<S>) => T Same as Flow function(S, ...T): U
Annotating a function's this parameter function f(this: {key: T}) Same as TS @this {S}
Generic function function f<T>(x : type) {} Same as TS Same as TS @template X, Y, ...
Generic function type <X>(x: S, ...) => T Same as TS Same as TS
Generic type application f<S>(arg) Same as TS Same as TS @type {!F<S>} This syntax can’t be easily supported in JS parsers, an alternative is funName::<type>().
Generic type application without call f<S> N/A N/A Added in TS 4.7. Generic functions or other values can be instantiated without a call-site. As above, this can’t be supported as-is in JS.
Bounded polymorphism <S extends T> <S: T> Same as Flow N/A
Dotted/variadic polymorphism type F<T extends any[]> = (x: [S, ...T]) => [...T]; Same as TS N/A N/A Added in TS 4.0.
Union type S | ... | T Same as TS Same as TS Same as TS
Maybe / option type N/A ?T Same as Flow ?T or T= In Flow, ?T allows null and undefined. Hegel only allows undefined. Closure compiler defines nullable types (?) and optional types (=).
Intersection type type & type Same as TS N/A N/A
Top type unknown mixed Same as TS *
Unsafe / dyn type any Same as TS N/A ?
Function top type Function (...$ReadOnlyArray<empty>) => mixed Same as TS
Bottom type never empty N/A N/A Added in TS 2.0, previously null/undefined acted like bottom
Undefined type undefined void Same as TS Same as TS
Null type null Same as TS Same as TS Same as TS
Inexact object type { x: S; y: T; } {x: S, y: T, ...} {x:S, ...} Same as Flow Flow prefers , over ; but both are accepted as field separators. Hegel has “hard” object types by default, so literal ellipses are needed for “soft” semantics. Closure compiler allows bare keys, which have any type.
Exact object type N/A {x: S, y: T} {x: S, y: T} TS doesn’t have exact object types, but you can encode them https://fettblog.eu/typescript-match-the-exact-object-shape/ Flow plans to deprecate the {||} syntax at some point in the future (~1 year), as exact object types are the default now
Object type spread type T = {...S}
Object top type object interface {} Object Object
Interfaces interface I { x: S; } Same as TS N/A (type aliases used instead) @interface In Hegel, type aliases can be used in an implements clause
Interface getter/setter interface I { get p(): number; set p(x : S); } Same as TS (setter return type required by Flow) N/A
Index signature { [key: S] : T } Flow does not require key name, {[S]: T} is valid as well N/A N/A This syntax is supported in Hegel but appears to be buggy. Index signatures are also allowed in TS inside of class bodies, optionally with a static specifier.
Class interface declaration class Foo implements Bar { ... } Same as TS Same as TS @implements {ClassName} Hegel implements from type aliases
Override declaration class C extends D { override m() { … } } N/A N/A @override Added in TS 4.3.
Abstract class abstract class C { abstract m() : S; } N/A N/A @abstract
Optional property { key?: T; } Same as TS { key : ?T } N/A
Call signature { (x: S, ...): T; ... } { (S ...): T, ... } N/A Hegel parses the Flow syntax but it appears to be buggy.
Constructor signature { new (x: S): T; } or new (x: S) => T N/A N/A Flow will understand the first TS example type, but interpret it as a property “new” with a function type.
Cast <T>expr or expr as T Same as TS N/A /** @type {!T} */ (expr) For Flow see v0.219.0 release notes
Assertion (cast without change of type) expr satisfies T N/A N/A Added in TS 4.9. Flow parses for error reporting purposes.
Non-null assertion expr! N/A N/A
Literal value type assertion “literal” as const N/A N/A Added in TS 3.4. Flow parses for error reporting purposes.
Interface declaration interface extends Parent, ... {} Same as TS N/A
Inline interface ? type T = interface { }
Type alias type A = T Same as TS Same as TS @typedef { ... }
Type alias generics type F<X> = S Same as TS Same as TS N/A
Generic parameter variance type F<in out X> = S type F<+T> = ...; or type F<-T> = ...; N/A N/A Added in TS 4.7. Flow parses for error reporting purposes.
Type alias with default generic parameter type F<X = S> = T Same as TS Same as TS N/A Type application differs between TS and Flow. TS would use F while Flow would use F<> for the default argument
Module type export export type Foo = type0 Same as TS Same as TS N/A TS allows type exports in ordinary exports, but as of 3.8 allows Flow’s type export syntax.
Module type import import type { Foo } from "./m.js" Same as TS Same as TS N/A See note above.
Inline type import import { type Foo } from "./m.js" Same as TS N/A N/A
Type reflection type T = typeof expr Same as TS type T = $TypeOf<expr>; {typeof expr}
Typeof import N/A import typeof foo from "./m.js" N/A N/A
Key type operator keyof type $Keys<type> Same as Flow N/A
Value type operator N/A $Values<type> Same as Flow N/A
Readonly property {readonly x: T} {+key: T} N/A N/A In Flow, + is considered a variance annotation.
Readonly class property class A {readonly foo: string} class A {+foo: string}
Writeonly property N/A {-key: T}
Readonly array readonly T[] $ReadOnlyArray<T>
Utility types in general Readonly<type> $ReadOnly<type> $Soft<T> N/A These are just examples of a large category of utility type constructors. Flow is moving away from prefixing non-expiremental utility types with $
Indexed access type type T = S[“key”] Same as TS $PropertyType<S, “key”> N/A
Optional indexed access type N/A type T = S?.["key"]
Mapped types type T<S> = { [Property in keyof S]: U; }; Same as TS N/A N/A
Conditional types type S = T extends U ? V : W; Same as TS N/A N/A
Opaque types N/A opaque type T = ...
Type predicates function p(x): x is T {...} Same as TS
Function overloads function a(x: S): S; function a(x: T): T; Like TS but requires declare before type only definitions