打字稿:基于输入值的函数的返回类型(枚举)

时间:2018-10-01 14:20:04

标签: typescript enums typescript-typings overloading conditional-types

我正在将一些设置存储到本地存储中,当我从存储中获取值(理想情况下还插入)时,我想键入响应。

从我所见,最好的方法似乎是使用函数重载。所以这就是我现在所拥有的并且可以正常工作:

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)
}

我不喜欢这种解决方案的地方是,可能会忘记在枚举中为重载类型定义添加一个新元素。有没有一种方法可以强制处理所有枚举值?还是有一种更好的方法可以完全做到这一点?

我认为这很简单,即从值hasOnboarded到返回类型boolean的映射,等等,但这显然不那么容易。

在我看来conditional types可能会解决此问题,但我无法完全了解它的工作原理。

我也看到了this的方法,但这似乎有点过多的开销。

任何见识将不胜感激!

1 个答案:

答案 0 :(得分:3)

您可以使用额外的类型在枚举和承诺返回类型之间进行映射。然后,我们向getSettings添加一个通用参数,该参数扩展了SettingsKey枚举,并使用该通用类型索引到映射类型。泛型参数将根据我们指定为参数的枚举成员来推断。

如果映射类型不包含枚举的所有键,则函数会出错。

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> {
   ///...
}