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
