2018-10-17
Both Flow and TypeScript provide several utility types. Here I've taken Flow's utility types and compiled some examples to show the equivalent syntax in TypeScript. The examples are (mostly) taken straight from the Flow docs.
Disclaimer: I don't use Flow. I may miss some less obvious features - please let me know if I do!
$Keys<T>
🔗TypeScript just uses keyof
, though you could define type $Keys<T> = keyof T
;
; // $Keys<typeof countries>
;
; // Error
$Values<T>
🔗Easily defined as T[keyof T]
, can be wrapped as type $Values<T> = T[keyof T]
if desired.
; // $Values<T>
;
// The following two types are equivalent:
;
;
; // OK, if in a module context
; // OK
; // Error
$ReadOnly<T>
🔗Can be easily defined using mapped types. The TypeScript handbook actually provides it as an example!
;
;
;
$Exact<T>
🔗$Exact<T>
doesn't quite make sense in TypeScript. If you specify the type of an object when defining an object literal, you will get an error if you try to provide more properties.
;
; // Error
However, it may sometimes be desirable to check later. In this case, it is possible to check if two types are exactly equal, and cause a type error if they are not. The conditional-type-checks library makes this fairly painless. The AssertTrue
and IsExactType
types have been extracted from it for purposes of demonstration.
;
;
;
;
$Diff<A, B>
🔗Diff
in TypeScript is commonly used for union types, however the $Diff
defined by Flow can easily be defined in TypeScript as well.
There are three similar ways to represent $Diff
, each has its advantages. While $Diff2
below is closer to the diff used by Flow, the $Diff
implementation below is safer.
;
;
;
;
;
;
;
;
;
;
; // Error
; // Ok, as in Flow
; // Error
; // Error
Note that the above $Diff
implementations will not complain if you try to remove properties which do not exist in A
. There isn't a standard way to raise a compile time type error in TypeScript, but it can be achieved by resolving the type to never
and causing an error where we try to assign an object to never
.
;
;
;
;
;
;
;
;
; // Still Ok
; // Error
However, this implementation still does not quite match Flow's $Diff
type. In Flow's $Diff
type, Flow will allow keys that don't exist in A
to exist in B
if they are defined with | void
. TypeScript's equivalent is | undefined
, so here's one last implementation.
;
;
;
;
;
;
;
;
;
; // Still Ok, other is optional
; // Error
$Rest<A, B>
🔗$Rest
is much simpler to represent with TypeScript. $Rest<A, B>
returns an object with A
's properties that are not B
's properties. Following Flow's behavior, the remaining properties are marked optional.
;
;
;
$PropertyType<T, k>, $ElementType<T, K>
🔗Like $Keys
, there's not much point in defining this in TypeScript. You can just use T['key']
.
;
;
;
;
; // Error
$NonMaybeType<T>
🔗This can be trivially implemented using the built in Exclude
.
;
;
; // => string
$ObjType<T, F>, $TupleMap<T, F>
🔗This is a bit more complicated, TypeScript doesn't have the ability to "call" a function type like Flow does, but it should be possible to write types which provide the same behavior.
Here's a few examples, taken from the Flow docs and translated to TypeScript.
// Run
;
;
; // Ok
; // Ok
; // Error
; // Error, c doesn't exist
// Props
;
;
;
promises;
// Tuple Run
// Unfortunately this only works when arr functions return a single type.
;
;
;
;
; // Error
$Call<F>
🔗It isn't currently possible to completely represent $Call
with TypeScript as it requires support for variadic kinds, which has been on the roadmap for several versions. However, for functions with a static return type, it is possible to use the built in ReturnType<T>
to extract a the return type of a function.
Class<T>
🔗Is not quite possible in TypeScript, there's no way to recover the constructor type from any instance type. (T['constructor']
is just Function
)
However, it is mostly unnecessary in TypeScript, just use typeof
and the class name.
;
Store;
ExtendedStore;
// To make this error, add a property to Store that is not in Model.
Model; // No error
$Shape<T>
🔗Is identical to Partial<T>
in TypeScript.