Typescript 无法键入每个键都映射到泛型值的对象
我在键入一个对象时遇到一些问题,其中每个键都映射到一个通用值 我已将我的代码简化为以下最小可复制示例:Typescript 无法键入每个键都映射到泛型值的对象,typescript,Typescript,我在键入一个对象时遇到一些问题,其中每个键都映射到一个通用值 我已将我的代码简化为以下最小可复制示例: export type Action<T extends string, P> = { type: T; error: false; payload: P; }; type Event = { action: string; [trait: string]: string; }; type Handlers = { [key: string]:
export type Action<T extends string, P> = {
type: T;
error: false;
payload: P;
};
type Event = { action: string; [trait: string]: string; };
type Handlers = {
[key: string]: <T extends string, P>(action: Action<T, P>) => Event;
};
export type ActionAType = Action<
"ACTION_A",
{ id: number; a: string; }
>;
export type ActionBType = Action<
"ACTION_B",
{ id: number; b: string }
>;
const HANDLERS: Handlers = {
"QUERY_GROUP_START": (action: ActionAType) => {
return { action: "START", a: action.payload.a };
},
"QUERY_GROUP_CONTINUE": (action: ActionBType) => {
return { action: "CONTINUE", id: action.payload.id };
}
};
我之所以需要这种模式,是因为我在Redux中间件中有一组操作处理程序
中间件
功能的工作方式如下:
动作
)export const coreAnalytics = (
customHandlers: Handlers
) => () => (next: (action: Action) => void) => (action: Action) => {
const customHandler: (action: Action) => Event =
customHandlers[action.type];
if (customHandler) {
const analyticsEvent: Event = customHandler(action);
...
}
...
};
请注意,此处没有用于操作的联合类型。如果我们有这个功能,那么将其重写为一个打开操作类型并处理每个操作的函数将非常简单
我这里有一个游乐场链接:
这样想:在类型为处理程序的对象中,调用函数属性之一时,唯一的保证是其操作
参数将是操作
。T
可以是任何string
,P
可以是任何东西。这使得在将属性分配给处理程序
对象时要求任何更具体的保证都是错误的。在这两种情况下,您要求action
具体为ActionAType
和ActionBType
,这意味着您要求T
具体为'action\u A'
和'action\u B'
,而P
具体为{id:number;A:string;}
和{id:number;b:string}
。这对于如何键入处理程序来说太具体了
我同意Federkun的观点,即最好的方法是不显式地键入处理程序
(事实上,您可能根本不需要处理程序
,甚至不需要作为别名)。如果没有显式类型,对象上的每个属性都有自己的较窄类型,并有关于T
和p
的相关保证
如果您的完整代码有某些原因需要在处理程序上显式键入,那么您可能需要更新/扩展您的示例以反映这一点。常量处理程序:处理程序
会释放指定值的类型信息,因此
在我看来,您可以只键入一个处理程序:(action:action)
为什么这里需要处理程序作为一种类型?它会有什么用途?为什么不能是类型处理程序=类型处理程序?@Federkun好问题,我已经尽可能地更新了这个问题来解释这一点。Redux委员会通常不再将操作作为联合类型键入。Redux maintainer@phry有一个article关于这一点:我将在稍后更详细地了解您的问题,但肯定有一些方法可以避免TS问题,而不是直接解决它。这是由于的概念。您是否尝试过使用接口而不是键入。如果您的操作是``导出接口法案`的接口,它会使事情变得更简单离子{type:string;error:boolean;payload:any;};``这是非常有见地的,您是对的,它需要更多的上下文,所以我编辑了我的问题,以便有更多的上下文来解释我为什么需要它。
export const coreAnalytics = (
customHandlers: Handlers
) => () => (next: (action: Action) => void) => (action: Action) => {
const customHandler: (action: Action) => Event =
customHandlers[action.type];
if (customHandler) {
const analyticsEvent: Event = customHandler(action);
...
}
...
};
const asHandlers = <HS extends Handlers>(hs: HS) => hs
const HANDLERS_TYPED = asHandlers({
"QUERY_GROUP_START": (action: ActionAType) => {
return true;
},
"QUERY_GROUP_CONTINUE": (action: ActionBType) => {
return false;
}
})