我正在尝试推断配置对象的类型,该配置对象的属性由参数描述数组定义。
简而言之:
// Based on the following array...
const params = [
{ id: "max", example: 75 },
{ id: "label", example: "My Label" },
];
// ...extract values from a request, creating a structure like...
const config = {
max: 100,
label: "Max Items",
};
// ... with type:
{ max: number, label: string }
这就是我的代码所取得的成就。
// A simple parameter description interface
type ConfigParameter<IdType, ValueType> = Readonly<{
// The `IdType` is necessary to get a stricter type
// parameter instead of a generic `id: string;`. This will be needed
// later when we infer the type of the `config` object.
id: IdType;
example: ValueType;
}>;
// Configuration parameters ------------------------------------
const max: ConfigParameter<"max", number> = {
id: "max",
example: 100,
};
const label: ConfigParameter<"label", string> = {
id: "label",
example: "My Label",
};
const configParams = [max, label] as const;
// Extracted configuration object ------------------------------
// At some point, the application uses the parameter descriptors
// above to extract data from a request. This is the implementation
// I have so far:
type Config<T extends Readonly<Array<ConfigParameter<string, any>>>> = {
[key in T[number]["id"]]: T[number]["example"];
};
const config: Config<typeof configParams> = {
max: 75,
label: "Some index",
};
现在的问题是,中的所有属性config
都具有type number | string
,而不是具有各自的类型:
// Expected type
{ max: number, label: string }
// Actual type
{ max: number | string, label: number | string }
我知道为什么会得到这个结果,但是我不知道如何分别限制每个键的类型。
有什么建议?
干得好:
type Config<T extends ReadonlyArray<ConfigParameter<string, any>>> = {
[K in T[number]["id"]]: Extract<T[number], { id: K }>["example"]
};
此处的区别是使用Extract
,这是一种实用程序类型,可将相关的部分从联合中取出。应该可以根据需要工作。您可以使用以下命令使其更漂亮(输出,而不是定义):
type Config<T extends ReadonlyArray<ConfigParameter<string, any>>> = {
[K in T[number]["id"]]: Extract<T[number], { id: K }>["example"]
} extends infer O
? { [P in keyof O]: O[P] }
: never;
现在,您将获得所需的强类型:
const config: Config<typeof configParams> = {
max: 75,
label: "Some index"
};
/* const config: {
max: number;
label: string;
} */
好吧,希望能有所帮助;祝好运!
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句