Skip to content

Instantly share code, notes, and snippets.

@thecotne
Last active November 22, 2023 20:08
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save thecotne/6e5969f4aaf8f253985ed36b30ac9fe0 to your computer and use it in GitHub Desktop.
Save thecotne/6e5969f4aaf8f253985ed36b30ac9fe0 to your computer and use it in GitHub Desktop.
Type-level conditions in Flow

Type-level conditions in Flow

click here to play with it -> flow.org/try/...

Helper Types

// X must be Assignable to boolean
// if (X is Assignable to true) -> Then
// else -> Else
type $If<X: boolean, Then, Else = empty> = $Call<
    & ((true, Then, Else) => Then)
    & ((false, Then, Else) => Else),
    X,
    Then,
    Else,
>;

// X must be Assignable to boolean
// if (X is Assignable to true) -> false
// else -> true
type $Not<X: boolean> = $If<X, false, true>;

// X must be Assignable to boolean
// Y must be Assignable to boolean
// if (X is Assignable to true) -> Y
// else -> false
type $And<X: boolean, Y: boolean> = $If<X, Y, false>;

// X must be Assignable to boolean
// Y must be Assignable to boolean
// if (X is Assignable to true) -> true
// else -> Y
type $Or<X: boolean, Y: boolean> = $If<X, true, Y>;

// if (A is Assignable to B) true
// else false
type $Assignable<A, B> = $Call<
    & ((B, true, false) => true)
    & ((A, true, false) => false),
    A,
    true,
    false,
>;

Usage

type User = {|
    id: string,
    name: string,
|}

type UserWith<Flags> = {|
    ...User,
    ...$If<$Assignable<'profile', Flags>, {| profile: string |}, {||}>,
    ...$If<$Assignable<'role', Flags>, {| role: string |}, {||}>
|}

;({
    id: 'string',
    name: 'string'
}: User) // ok

;({
    id: 'string',
    name: 'string',
    profile: ''
}: User) // err

;({
    id: 'string',
    name: 'string',
    profile: ''
}: UserWith<'profile'>) // ok

;({
    id: 'string',
    name: 'string',
    role: ''
}: User) // err

;({
    id: 'string',
    name: 'string',
    role: ''
}: UserWith<'role'>) // ok

;({
    id: 'string',
    name: 'string',
    profile: '',
    role: ''
}: UserWith<'role' | 'profile'>) // ok
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment