[英]How do I infer the exact type of an object function parameter in TypeScript?
我有一个 object ,其属性使用通用模板文字键入,该模板文字需要某个提供的(作为通用类型参数)substring 出现在字符串中。 目前,如果提供了无效值,则错误是无法将值分配给模板文字。
我想使错误消息包含带有自定义消息的类型。 例如Type 'never' is not assignable to type 'ErrorMessage<"You cannot do that.">'.
我见过这样做的库,但我不知道在这种情况下如何做。 我有一个创建这个的泛型,但是当它试图让它与对象一起工作时,属性不够窄。
我已经完成了以下工作:
interface ErrorMessage<T> {
__msg: T;
}
type Substring<
str extends string,
substr extends string
> = str extends `${string}${substr}${string}`
? str
: ErrorMessage<`No match: '${str}' does not contain '${substr}'`>;
type Substrings = {
bar: "aaa";
};
type Foo<T extends { [K in keyof Substrings]: string }> = {
[K in keyof T & keyof Substrings]: Substring<T[K], Substrings[K]>;
};
type Infer<T extends { [K in keyof Substrings]: string }> = {
[K in keyof T]: T[K];
};
const helper =
<T extends { [K in keyof Substrings]: string }>(val: Infer<T>) =>
(val2: Foo<T>) =>
val2;
const foo = helper({
bar: "has bar aaa",
})({
bar: "has bar aaa",
});
这在理论上可行,但重复的 function 调用很尴尬。 有什么办法可以让helper
“自给自足”? 我尝试过的所有其他变体最终都会将 object 的属性类型推断为string
。 主要问题是 TypeScript 在使用其他工作的泛型时无法推断T
为helper
。
我可以传递 type 参数,但这需要将 object 单独定义as const
,然后使用typeof
,这也很尴尬。
作为一种稍微不同的方法,以下方法几乎可以工作,除了K
不是Foo
映射中Substrings
的有效索引:
type Foo<T extends { [K in keyof T & keyof Substrings]: string }> = {
[K in keyof T]: Substring<T[K], Substrings[K]>;
};
const helper = <T extends { [K in keyof Substrings]: string }>(val: Foo<T>) =>
val;
我可能已经用这种特殊的方法走上了死胡同。 如果你知道或能想出不同的方法,我很高兴。 我对我目前所拥有的东西没有特别的亲和力,这只是我迄今为止最终得到的东西。
我感觉会有一些 function 过载和currying,但我不够熟练来实现它。
提前致谢。
更新:带有常规错误消息的简单示例:
type Substring<substr extends string> = `${string}${substr}${string}`;
type Substrings = {
bar: "aaa";
};
type Foo<T extends { [key: string]: string }> = {
[K in keyof T]: Substring<T[K]>;
};
const helper = <T extends Foo<Substrings>>(val: T) => val;
const foo = helper({
bar: "has bar aaa",
});
这是一种可能的方法:
const helper = <T extends Record<keyof Substrings, string>>(
t: { [K in keyof T]: K extends keyof Substrings ? (
T[K] extends `${string}${Substrings[K]}${string}` ?
T[K] : ErrorMessage<`No match: '${T[K]}' does not contain '${Substrings[K]}'`>
) : T[K] }
) => t;
类型检查器在推断泛型类型参数时使用的算法有点繁琐。 编译器非常擅长从同态映射类型推断,这意味着它通常可以从类型{[K in keyof T]: ...T[K]...}
T
但是T[K]
出现在...T[K]...
中的特定位置与推理的成功程度有很大关系。
我使用的一个经验法则是,如果您希望编译器从条件类型推断泛型X
,您应该确保X
直接显示为检查类型,例如X extends... ? ... : ...
X extends... ? ... : ...
由于我们希望编译器推断T[K]
,因此我们希望T[K] extends...
因此T[K] extends `${string}${Substrings[K]}${string}`? ...
T[K] extends `${string}${Substrings[K]}${string}`? ...
类型。 您可能可以将其重构为它自己的命名类型别名,但这可能会产生奇怪的附加效果,我不想在这里讨论。
无论如何,让我们测试一下:
const foo1 = helper({
bar: "has bar aaa",
}); // okay
const foo2 = helper({
bar: "oopsie doodle" // error!
//~ <-- 'ErrorMessage<"No match: 'oopsie doodle' does not contain 'aaa'">'
})
看起来不错。 您会收到您正在寻找的错误消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.