skip to Main Content

I am trying to type action names but something I’m doing wrong.

It throws an error when I try to use it on reducer function when trying to call updateProduct function, even though I typed action names correctly.

Property 'update' does not exist on type 'ActionDelete'.

Here is the way I tried to implement it.
I’ve created an enum for action names and used them according to action type and type Action is an alias which is either ActionUpdate or ActionDelete.

enum ActionTypes {
    update = 'update',
    delete = 'delete'
}

interface ActionUpdate {
    type: ActionTypes.update;
    update: string;
}

interface ActionDelete {
    type: ActionTypes.delete;
    delete: string;
}

type Action =
    | ActionUpdate
    | ActionDelete

I’ve created an interface for a call signature with positional arguments

 interface ActionProps {
    (
        product: Product,
        value: Value,
        cart: Cart,
        action?: Action
    ): void;
}

And here is the rest of usage of Action in reducer function.
Reducer function

 const Reducer = (
    product: Product,
    value:Value,
    cart: Cart,
    action: Action,
) => {

    switch (action.type) {
        case 'update':
            updateProduct( product, value, cart);
            break;
        default: {
            throw new Error('Unknown type');
        }
    }
};

And as an example here is updateProduct functon for update

const updateProduct: ActionProps = ( product, value, cart, action) => {
    cart.name = action.update;  // Error throws here on "action.update"
};

Here is a link for testing

Any help will be appreciated

2

Answers


  1. This is happening because your ActionProps interface has an optional parameter action?: Action where Action can be either ActionDelete or ActionUpdate – in your code, you’re assuming that ActionProps will only ever return an ActionUpdate type and therefore you don’t handle the case where the action could be of ActionDelete type

    The easiest option would be to set the action inside of ActionProps to ActionUpdate i.e. action?: ActionUpdate (assuming that you won’t return an ActionDelete action in this scenario)

    Alternatively, it would be best if you restructured your types to be more explicit as to what you’re expecting so you can avoid these types of errors

    Login or Signup to reply.
  2. You can make your ActionProps interface generic, defaulting to Action. This way, you can optionally provide a specific action if you need to.

    interface ActionProps<A extends Action = Action> {
        (product: Product, value: Value, cart: Cart, action?: A): void;
    }
    

    Then in your definition of updateProduct, pass the right action type:

    const updateProduct: ActionProps<ActionUpdate> = (product, value, cart, action) => {
        if (!action) return;
    
        cart.name = action.update; // okay
    };
    

    Playground


    You could just use a type alias instead of an interface:

    type ActionProps<A extends Action = Action> = (product: Product, value: Value, cart: Cart, action?: A) => void;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search