Typescript: Returtyp för funktion baserat på inmatningsvärde (enum)
Jag lagrar några inställningar i lokal lagring och jag skulle vilja skriva svaren när jag får (och helst också infogar) värden från/till lagringen.
Från vad jag har sett verkar det bästa sättet vara att använda funktionsöverlagring. Så detta är vad jag har nu och det fungerar:
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 jag inte gillar med denna lösning är att det är möjligt att glömma att lägga till ett nytt element i enum för överbelastade typdefinitioner. Finns det ett sätt att säkerställa att alla enum-värden hanteras? Eller finns det kanske ett bättre sätt att göra detta överhuvudtaget?
Jag trodde att detta skulle vara en enkel sak, en mappning från värdet hasOnboarded till returtypen boolean osv, men det är uppenbarligen inte så enkelt.
Det verkar för mig som att villkorliga typer kan lösa det här problemet, men jag kan inte riktigt förstå hur det fungerar.
Jag såg också detta tillvägagångssätt, men det verkar vara lite för mycket överhuvudtaget.
All insikt skulle uppskattas mycket!
Svar #1
Du kan använda en extra typ för att mappa mellan enum och promise-returtypen. Vi lägger sedan till en generisk parameter till getSettings som utökar SettingsKey-enum och använder den generiska typen för att indexera in i mappingtypen. Den generiska parametern kommer att härledas baserat på den enum-medlem vi anger som argument.
Om mappningstypen inte innehåller alla nycklar i enum kommer vi få ett fel på funktionen.
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> {
///...
}
