我正在尝试创建一个提供一些基本返回类型的通用设置实用程序。我们的应用程序将所有设置存储在集中式字典中,我想提供可能类型的映射,而不是手动指定每个键的类型。
举个例子,假设我们有设置键的映射:
const UserSettings = {
DEFAULT_ORGANIZATION: 'user_profile.default_organization',
THEME: 'user_profile.theme'
} as const;
我想创建一个相应的地图,如下所示:
type UserSettingsTypes = {
'user_profile.default_organization': boolean;
'user_profile.theme': { primary: string; secondary: string };
};
这样我就可以编写一个设置查找函数,如下所示:
const organization = readSetting<UserSettingsTypes>(UserSettings.DEFAULT_ORGANIZATION);
其中
organization
具有正确的 boolean
类型。
我尝试向
readSetting
添加一个泛型,如下所示:
const readSetting = <T extends Record<string, unknown>, K = keyof T>(key: K): T[K] => {
// ...
};
但它抱怨“类型‘K’不能用于索引类型‘T’”
是否可以提供这样的映射返回类型?
如果是这样,我应该如何构造
K
,以便它可以正确返回T
中的映射类型?
这是显示问题的示例:https://tsplay.dev/m0d2qm
从概念上讲,你想要类似的东西
declare const readSetting:
<T extends object, K extends keyof T>(key: K) => T[K]
其中
K
约束 到 keyof T
。不幸的是,你不能调用像 readSetting<UserSettingsTypes>(UserSettings.DEFAULT_ORGANIZATION)
这样的泛型函数,你可以手动 specify T
但有编译器 infer K
为你服务。 TypeScript 不支持 microsoft/TypeScript#26242 中要求的部分类型参数推断。您要么必须让编译器推断 T
和 K
(如果没有 T
类型的参数,这是不可能的),或者您必须手动指定 T
和 K
(这是多余的)对于 K
)。不,使用像 K = keyof T
这样的 type argument default没有帮助;你只会得到默认值而不是推理。
除非实现了 microsoft/TypeScript#26242,否则您需要以某种方式解决它。我在这里使用的最常见的解决方法是 currying,您可以将单个通用函数拆分为多个。在你的情况下看起来像:
declare const readSetting:
<T extends object>() => <K extends keyof T>(key: K) => T[K]
现在您可以调用
readSetting<UserSettingsTypes>()
,手动指定 T
。这将返回一个类型为 <K extends keyof UserSettingsTypes>(key: K) => UserSettingsTypes[K]
的新泛型函数,您可以使用函数参数调用该函数,并且将为您推断出 K
:
const organization =
readSetting<UserSettingsTypes>()(UserSettings.DEFAULT_ORGANIZATION);
// const organization: boolean
所以,虽然中间有那个奇怪的函数调用
()
,但它非常接近您最初想要的,并且它为您提供了您期望的返回类型。