问题描述
限时送ChatGPT账号..假设我有这样的类型:
type TInfoGeneric<TType extends string, TValue> = {
valueType: TType,
value: TValue, // Correspond to valueType
}
为了避免重复我自己,我创建了一个类型映射,其中列出了可能的 valueType
并将 valueType
与值的类型相匹配.
To avoid repeating my self, I create a type map that list the possible valueType
and matches valueType
with, well, value's type.
type TInfoTypeMap = {
num: number;
str: string;
}
现在,要实际创建 TInfo
,我使用映射类型将所有类型映射到 TInfoGeneric
中,然后只获取它的值.
Now, to actually create TInfo
, I use mapped type to map all types into TInfoGeneric
and then get only value side of it.
type TAllPossibleTInfoMap = {
[P in keyof TInfoTypeMap]: TInfoGeneric<P, TInfoTypeMap[P]>;
};
type TInfo = TAllPossibleTInfoMap[keyof TAllPossibleTInfoMap]; // TInfoGeneric<"num", number> | TInfoGeneric<"str", string>
然后,为了为所有类型定义处理程序,我为处理程序创建了另一个映射类型.
Then, to define handlers for all types, I create another mapped type just for handlers.
type TInfoHandler = {
[P in keyof TInfoTypeMap]: (value: TInfoTypeMap[P]) => any
};
const handlers: TInfoHandler = {
num: (value) => console.log(value.toString(16)),
str: (value) => console.log(value),
}
最后,为了实际使用处理程序,我创建了一个这样的函数:
And finally, to actually use the handler, I create a function like this:
function handleInfo(info: TInfo) {
handlers[info.valueType](info.value); // Error
}
我收到此错误:
Argument of type 'string | number' is not assignable to parameter of type 'number & string'.
Type 'string' is not assignable to type 'number & string'.
Type 'string' is not assignable to type 'number'.
通常情况下,handlers[info.valueType]
可以是一个 ((value: number) => any) | 是可以理解的.((value: string) => any)
.但是,在这种情况下:
Normally, it's understandable that handlers[info.valueType]
may be a ((value: number) => any) | ((value: string) => any)
. However, in this case:
info.valueType
是'num'
,那么我们可以确定handlers[info.valueType]
是(值:数字)=>any)
和 info.value
是 number
.因此,可以使用 info.value
调用 handlers[info.valueType]
.如果info.valueType
是'str'
,那么我们可以确定handlers[info.valueType]
是(值:字符串) =>any)
和 info.value
是 string
.因此,可以使用 info.value
调用 handlers[info.valueType]
.
If info.valueType
is 'num'
, then we can be sure that handlers[info.valueType]
is (value: number) => any)
and info.value
is number
. Thus, handlers[info.valueType]
can be called with info.value
.
If info.valueType
is 'str'
, then we can be sure that handlers[info.valueType]
is (value: string) => any)
and info.value
is string
. Thus, handlers[info.valueType]
can be called with info.value
.
我不确定这是否是 Typescript 的限制,但是否可以以这种风格编写代码以进行类型检查?
I'm not sure if this is Typescript limitation or not, but is it possible to write the code in this style so that it's type-checked?
推荐答案
是的,这里没有适合您的方便且类型安全的解决方案.我已经在 microsoft/TypeScript#30581 上打开了一个问题,但我没有不希望它得到解决.
Yeah, there's no convenient and type-safe solution for you here. I've opened an issue at microsoft/TypeScript#30581 about this but I don't expect it to be addressed.
我看到了两种主要的前进方向.一种是只使用 类型断言,因为你理所当然地知道比编译器在这里做的更多.可能是这样的:
I see two main ways forward. One is to just use a type assertion, since you legitimately know more than the compiler does here. It could be like this:
function handleInfo(info: TInfo) {
// assert your way out. Not type safe but convenient!
(handlers[info.valueType] as (x: number | string)=>any)(info.value);
}
现在没有错误.它不是类型安全的.但它很方便,并且不会改变发出的 JavaScript.
Now there's no error. It's not type safe. But it's convenient and doesn't change the emitted JavaScript.
或者您可以尝试通过案例引导编译器并向其证明一切正常.这很复杂、很脆弱,并且会产生运行时影响:
Or you could try to walk the compiler through the cases and prove to it that all is fine. This is complex, brittle, and has runtime effects:
const typeGuards: {
[P in keyof TInfoTypeMap]: (x: TInfoTypeMap[keyof TInfoTypeMap])=>x is TInfoTypeMap[P];
} = {
num: (x:any): x is number => typeof x === "number",
str: (x:any): x is string => typeof x === "string"
}
function narrowTInfo<K extends keyof TAllPossibleTInfoMap>(
x: TInfo, v: K): x is TAllPossibleTInfoMap[K] {
return typeGuards[v](x.value);
}
function handleInfo(info: TInfo) {
if (narrowTInfo(info, "num")) {
handlers[info.valueType](info.value); // okay
} else {
handlers[info.valueType](info.value); // okay
}
}
这可行,但令人讨厌.所以我推荐一个断言.
That works but is obnoxious. So I'd recommend an assertion.
希望有所帮助;祝你好运!
Hope that helps; good luck!
这篇关于如何制作“处理程序"查找“调度员"正确键入样式函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
更多推荐
[db:关键词]
发布评论