Typescript: Returtype for funksjon basert på inputverdi (enum)
Jeg lagrer noen innstillinger i lokal lagring, og jeg vil gjerne skrive svarene når jeg får (og ideelt sett også setter inn) verdier fra/til lagringen.
Fra det jeg har sett, ser den beste måten ut til å være å bruke funksjonsoverlasting. Så dette er hva jeg har nå, og det fungerer:
export enum SettingsKey {
hasOnboarded = 'hasOnboarded',
phoneNumber = 'phoneNumber'
}
export async function getSetting(storage: Storage, key: SettingsKey.phoneNumber): Promise<string>
export async function getSetting(storage: Storage, key: SettingsKey.hasOnboarded): Promise<boolean>
export async function getSetting(storage: Storage, key: any) {
return storage.get(key)
}
Det jeg ikke liker med denne løsningen er at det er mulig å glemme å legge til et nytt element i enum i definisjonene av overbelastningstype. Finnes det en måte å sikre at alle enum-verdier blir håndtert? Eller er det kanskje en bedre måte å gjøre dette på samlet sett?
Jeg trodde dette ville være en enkel sak, en avbildning fra verdien hasOnboarded til returtypen boolean osv., men det er åpenbart ikke så enkelt.
Det ser ut for meg som om betingede typer kan løse dette problemet, men jeg klarer ikke helt å forstå hvordan det fungerer.
Jeg så også på denne tilnærmingen, men dette virker som litt for mye overhead.
Enhver innsikt vil bli svært verdsatt!
Svar #1
Du kan bruke en ekstra type for å kartlegge mellom enumen og promise-returtypen. Vi legger deretter til en generisk parameter til getSettings som utvider SettingsKey-enumet, og bruker den generiske typen til å indeksere inn i kartleggingstypen. Den generiske parameteren vil bli utledet basert på enum-medlemmet vi spesifiserer som et argument.
Hvis mappingtypen ikke inneholder alle nøklene til enumen, vil vi få en feil i funksjonen.
export enum SettingsKey {
hasOnboarded = 'hasOnboarded',
phoneNumber = 'phoneNumber'
}
type SettingsKeyReturnType = {
[SettingsKey.hasOnboarded]: boolean,
[SettingsKey.phoneNumber]: string
}
export async function getSetting<K extends SettingsKey>(storage: Storage, key: K): Promise<SettingsKeyReturnType[K]> {
return storage.get(key)
}
let a = getSetting(window.localStorage, SettingsKey.phoneNumber); // Promise<string>
let b = getSetting(window.localStorage, SettingsKey.hasOnboarded); // Promise<booelan>
// We can also define a set function in a similar way
export async function setSetting<K extends SettingsKey>(storage: Storage, key: K, value: SettingsKeyReturnType[K]): Promise<void> {
///...
}
