如何创建一个返回实现通用接口的匿名类的工厂

时间:2017-03-24 13:38:32

标签: generics typescript type-safety ngrx

我们正在使用带有Angular / TypeScript的ngrx。为了向Actions添加一些类型安全性,我们创建了以下

export interface TypedAction<T> extends Action {
    type: string;
    payload: T;
}

export class ExtensionRegistrationAction implements TypedAction<ExtensionRegistrationPayload> {
    readonly type = ExtensionActionTypes.REGISTER_EXTENSION;
    constructor(public payload: ExtensionRegistrationPayload) {}
}

export class ExtensionRegistrationSucceededAction implements TypedAction<void> {
    readonly type = ExtensionActionTypes.REGISTER_EXTENSION_SUCCESS;
    constructor(public payload: void) {}
}

export class ExtensionRegistrationFailedAction implements TypedAction<{messageCode: string}> {
    readonly type = ExtensionActionTypes.REGISTER_EXTENSION_FAILURE;
    constructor(public payload: {messageCode: string}) {}
}


export type ExtensionActions = ExtensionRegistrationAction
    | ExtensionRegistrationFailedAction
    | ExtensionRegistrationSucceededAction;

// The above lets us do the following
export function appExtensionsReducer(state: AppExtensionState = initialAppExtensionsState,
                                     action: ExtensionActions): AppExtensionState {
    switch (action.type) {
        case ExtensionActionTypes.REGISTER_EXTENSION: 
            const registerAction = action as ExtensionRegistrationAction;
            return {
                registrations: state.registrations.concat(registerAction.payload)
            };
        // Handle other actions...
        default: {
            return state;
        }
    }
}

为了摆脱锅炉位置代码,我想我可以创建一个生成这些类的函数。

export function createTypedActionConstructor<T>(type: string): TypedAction<T> {
    return class TypedActionImpl implements TypedAction<T> {
        readonly type = type;
        constructor(public payload: T) {}
    }
}

但是我得到一个错误,因为我返回的是实现TypedAction的类,而不是实例。错误说:

  

TS2322类型'typeof TypedActionImpl'不能分配给'TypedAction'类型。财产“类型”缺失。

我做了什么工作

以下代码通过要求两个声明来解决问题,一个用于实现T的接口,另一个用于创建该类型T的工厂函数。问题在于它对锅炉板代码膨胀没有多大帮助。

export function createTypedActionFactory<T>(type: string): (payload: T) => TypedAction<T> {
    return function(payload: T): TypedAction<T> {
        return {type, payload};
    }
}
// Now to create an action I need the two statements
export interface ExtensionRegistrationAction extends TypedAction<ExtensionRegistrationPayload> {}
export const createExtensionRegistrationAction = createTypedActionFactory<ExtensionRegistrationPayload>(
    ExtensionActionTypes.REGISTER_EXTENSION);

问题 是否无法从TypeScript返回泛型类的动态实现?

1 个答案:

答案 0 :(得分:2)

应该是:

export function createTypedActionConstructor<T>(type: string): { new (payload: T): TypedAction<T> } {
    ...
}

修改

另一种选择是添加多个功能签名:

export function createTypedActionConstructor(type: ExtensionActionTypes.REGISTER_EXTENSION_FAILURE): { new (payload: {messageCode: string}): ExtensionRegistrationFailedAction };
export function createTypedActionConstructor(type: ExtensionActionTypes.REGISTER_EXTENSION_SUCCESS): { new (payload: void): ExtensionRegistrationSucceededAction };
...