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 |