How to create a factory that returns anonymous classes that implement a generic interface

∥☆過路亽.° 提交于 2019-12-12 03:35:58

问题


We are using ngrx with Angular/TypeScript. To add some type safety to Actions, we created the following

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;
        }
    }
}

To get rid of the boiler place code, I thought I could create a function that generates those classes.

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

But I get an error because what I'm returning is the class that implements TypedAction, not the instance. The error says:

TS2322 Type 'typeof TypedActionImpl' is not assignable to type 'TypedAction'. Property 'type' is missing.

What I did get working

The following code gets around the problem by requiring two declarations, one for the interface that implements T and one for a factory function that creates that type T. The problem is that it doesn't help that much with boiler plate code bloat.

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);

Question Is it impossible to return a dynamic implementation of a generic class from TypeScript?


回答1:


should be:

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

Edit

Another option is to add multiple function signatures:

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 };
...


来源:https://stackoverflow.com/questions/43000982/how-to-create-a-factory-that-returns-anonymous-classes-that-implement-a-generic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!