haskell - Kanske en typ i typescript


Jag skulle vilja konstruera en Maybe a-typ i TypeScript à la Haskell:

data Maybe a = Just a | Nothing

Det verkar som att sättet att göra det på i typescript är:

interface Nothing { tag "Nothing }
type Maybe<T> = T | Nothing

Jag skulle vilja göra en funktion:

function foo(x : string) : Maybe<T> {
    return Nothing
}

liknande:

foo : String -> Maybe a
foo _ = Nothing

Dock fungerar detta inte i typescript. Vad är rätt sätt att returnera ett värde Nothing i typescript? Jag skulle vilja undvika att använda null om möjligt.

___________________________________________________-

Redigera: Det skulle vara riktigt trevligt om funktionen foo skulle returnera ett värde Nothing eftersom jag skulle vilja mönstermatcha på värdekonstruktor senare, dvs:

case blah blah of 
    | Just x -> x + x
    | Nothing -> "no words"

Svar #1

Beroende på fallet kan det vara void, undefined eller ? valfri modifierare för egenskaper och parametrar.

Det är:

function foo(x : string) : number | void {
    // returns nothing
}

void och undefined-typer är kompatibla, men det finns en viss skillnad mellan dem. Den förstnämnda är att föredra för funktioners returtyper, eftersom den sistnämnda kräver att en funktion har ett return-uttryck:

function foo(x : string) : number | undefined {
    return;
}

Maybe kan implementeras med generisk typ. Explicit Nothing-typ kan implementeras med unikt symbol:

const Nothing = Symbol('nothing');
type Nothing = typeof Nothing;
type Maybe<T> = T | Nothing;

function foo(x : string) : Maybe<number> {
    return Nothing;
}

Eller en klass (privata fält kan användas för att förhindra ducktyping):

abstract class Nothing {
    private tag = 'nothing'
}
type Maybe<T> = T | typeof Nothing;

function foo(x : string) : Maybe<number> {
    return Nothing;
}

Observera att klasser typsätter instanstypen för klassen och kräver användning av typeof när en klass refereras.

Eller ett objekt (om duck typing kan vara önskvärt):

const Nothing: { tag: 'Nothing' } = { tag: 'Nothing' };
type Nothing = typeof Nothing;
type Maybe<T> = T | Nothing;

function foo(x : string) : Maybe<number> {
    return Nothing;
}

Svar #2

enum Nothing {
  Nothing = 'Nothing'
}

type Maybe<A> = A | Nothing
type MaybeNumber = Maybe<number>

const isNothing = (m: MaybeNumber): m is Nothing => m === Nothing.Nothing 

const foo = (m: MaybeNumber) => {
  if (isNothing(m)) {
    return Nothing.Nothing
  } else {
    return m + 1
  }
}

foo(1) // ✔️
foo('Nothing') // ❌
foo(Nothing.Nothing) // ✔️

eller utan att använda en enum med en string literal type

const Nothing = '__nothing__'

type Maybe<A> = A | Nothing
type MaybeNumber = Maybe<number>

const isNothing = (m: MaybeNumber): m is Nothing => m === Nothing 

const foo = (m: MaybeNumber) => {
  if (isNothing(m)) {
    return Nothing
  } else {
    return m + 1
  }
}

foo(1) // ✔️
foo(Nothing) // ✔️
foo('__nothing__') // ✔️

eller med symboler

const nothing = Symbol('Nothing')
type Nothing = typeof nothing

type Maybe<A> = A | Nothing
type MaybeNumber = Maybe<number>

const isNothing = (m: MaybeNumber): m is Nothing => m.toString() === 'Symbol(Nothing)' 

const foo = (m: MaybeNumber) => {
  if (isNothing(m)) {
    return nothing
  } else {
    return m + 1
  }
}

foo(1) // ✔️
foo(nothing) // ✔️

leva på stackblitz

Relaterade artiklar