我目前正致力于使用TypeScript创建类似redux的库。基本动作如下所示:
interface ActionBase {
type: string;
payload: any;
}
然后我为每个动作类型扩展了动作界面。例如,对于按钮单击事件,我会有类似的内容:
interface ButtonClickAction extends ActionBase {
type: 'BUTTON_CLICK';
payload: {
// Include some kind of metadata in here
};
}
然后我添加了一些辅助函数
function isInstanceOfButtonClick(action: ActionBase ): action is ButtonClickAction {
return action.type === 'BUTTON_CLICK';
}
function buildButtonClickAction(payload): ButtonClickAction {
return {
type: 'BUTTON_CLICK',
payload,
};
}
问题是我正在为20多种不同类型的行动做这件事。有没有干这样做的方法?对于我需要的每一个动作:
"BUTTON_CLICK"
)ButtonClickAction
)buildButtonClickAction
)isInstanceOfButtonClick
)我可以使用类或函数来实现所有具体项目(1,4,5),但我没有干涸的方法来做2和3.现在,我对每个动作都有类似的东西:
const KEY = 'BUTTON_CLICK';
namespace ButtonClick {
export type Payload = {...}
export interface Action extends ActionBase {
type: typeof KEY;
payload: Payload;
}
}
let ButtonClick = makeActionValues<typeof KEY, ButtonClick.Payload, ButtonClick.Action>(KEY)
export default ButtonClick;
有更好的方法吗?
答案 0 :(得分:0)
类似于创建Action
工厂字典的函数,每个工厂都有适用于isInstance()
类型的buildAction()
和Action
方法?像这样:
interface ActionFactory<T extends string, P> {
isInstance(action: Action): action is Action<T, P>;
buildAction(payload: P): Action<T, P>;
}
interface Action<T extends string=string, P=any> {
type: T,
payload: P,
}
function getActionFactories<M extends object>(mappings: M): {[T in keyof M]: ActionFactory<T, M[T]>} {
const ret: any = {};
Object.keys(mappings).forEach((k: keyof M) => {
type T = keyof M;
type P = M[T];
ret[k] = class Act {
static isInstance(action: Action): action is Action<T, P> {
return action.type === k;
}
static buildAction(payload: P): Action<T, P> {
return new Act(payload);
}
type: T = k;
private constructor(public payload: P) { }
}
});
return ret;
}
您可以通过创建操作键到有效负载类型的映射来使用它:
const _: any = void 0;
const ActionPayloads = {
ButtonClick: _ as { whatever: string },
SomeOtherAction: _ as { parameter: number },
WhoKnows: _ as { notMe: boolean },
}
上面有点难看但是我可能是最干的......否则我需要指定两次关键名称;一次用于有效负载映射,一次用于密钥列表。然后你拨打getActionFactories()
:
const Actions = getActionFactories(ActionPayloads);
生成的Actions
对象有点像命名空间。观察:
const buttonClick = Actions.ButtonClick.buildAction({ whatever: 'hello' });
const someOtherAction = Actions.SomeOtherAction.buildAction({ parameter: 4 });
const whoKnows = Actions.WhoKnows.buildAction({ notMe: false });
const randomAction = Math.random() < 0.33 ? buttonClick : Math.random() < 0.5 ? someOtherAction : whoKnows
if (Actions.WhoKnows.isInstance(randomAction)) {
console.log(randomAction.payload.notMe);
}
这对你有用吗?
@darpa said:
我希望能够获得结果
的类型action.payload
好吧,要获取ButtonClick
的有效负载类型,您可以使用ActionPayloads
对象并执行以下操作:
const buttonClickPayload: typeof ActionPayloads.ButtonClick = {whatever: 'hello'};
const buttonClick = Actions.ButtonClick.buildAction(buttonClickPayload);
或者,如果您希望Actions
公开此类型,则可以向Payload
添加幻像ActionFactory
属性:
interface ActionFactory<T extends string, P> {
isInstance(action: Action): action is Action<T, P>;
buildAction(payload: P): Action<T, P>;
Payload: P; // phantom property
}
然后你可以像这样引用有效载荷类型:
const buttonClickPayload: typeof Actions.ButtonClick.Payload = {whatever: 'hello'};
const buttonClick = Actions.ButtonClick.buildAction(buttonClickPayload);
但请注意不要实际尝试使用Actions.ButtonClick.Payload
的值,因为它不会真正存在:
console.log(Actions.ButtonClick.Payload.whatever); // okay in TS but blows up at runtime.
希望有所帮助!