Redux Actions TypeScript Возвращаемый тип не работает - PullRequest
3 голосов
/ 24 января 2020

Итак, в основном, я пытаюсь вернуть типы для набора функций и могу соответствовать этому в моем редукторном редукторе.

Вот моя попытка:

actions.ts

export const SET_CART_ITEMS = "SET_CART_ITEMS";
export const SET_CART_TOTALS = "SET_CART_TOTALS";

export const ADD_CART_ITEM = "ADD_CART_ITEM";
export const REMOVE_CART_ITEM = "REMOVE_CART_ITEM";

export const SET_CART_LOADING = "SET_CART_LOADING";

export function setCart(cart: Cart) {
  return {
    type: SET_CART_ITEMS,
    cart
  } as const;
}

export function setTotals(totals: CartTotal) {
  return {
    type: SET_CART_TOTALS,
    totals
  }
}

export function addCartItem(cart: Cart) {
  return {
    type: ADD_CART_ITEM,
    cart
  } as const;
}

export function removeCartItem(cart: Cart) {
  return {
    type: REMOVE_CART_ITEM,
    cart
  } as const;
}

export function toggleCartLoading(loading: boolean) {
  return {
    type: SET_CART_LOADING,
    loading
  } as const;
}

export type CartActions = ReturnType<typeof setCart>| ReturnType<typeof addCartItem> | ReturnType<typeof removeCartItem> | ReturnType<typeof toggleCartLoading> | ReturnType<typeof setTotals>

reducer.ts

import { 
   CartActions,  
   ADD_CART_ITEM,
   REMOVE_CART_ITEM,
   SET_CART_ITEMS,
   SET_CART_TOTALS,
   SET_CART_LOADING 
} from '../../../actions';

export default (state: CartState = initialState, action: CartActions) : CartState => {
  switch (action.type) {
    case ADD_CART_ITEM:
      return {
        ...state,
        cart: {
          ...action.cart
        }
      }
    case REMOVE_CART_ITEM:
      return {
        ...state,
        cart: {
          ...action.cart
        }
      }
    case SET_CART_ITEMS:
      return {
        ...state,
        cart: action.cart
      }
    case SET_CART_TOTALS:
      return {
        ...state,
        totals: action.totals
      }
    case SET_CART_LOADING:
      return {
        ...state,
        loading: action.loading
      }
    default:
      break;
  }
  return state;
}

Это не работает вообще, ошибка Я вижу, что в переключателе редуктора говорится:

"Property 'cart' does not exist on type 'CartActions'.
  Property 'cart' does not exist on type '{ type: string; totals: CartTotal; }'."


Property 'loading' does not exist on type '{ readonly type: "SET_CART_ITEMS"; readonly cart: Record<string, CartItem>; } | { readonly type: "ADD_CART_ITEM"; readonly cart: Record<string, CartItem>; } | { ...; } | { ...; } | { ...; }'.
  Property 'loading' does not exist on type '{ readonly type: "SET_CART_ITEMS"; readonly cart: Record<string, CartItem>; }'.ts(2339)

Я что-то упускаю из виду? Мне бы очень хотелось, чтобы не нужно было вводить все действия интерфейсами вручную.

Вдохновение от https://gist.github.com/schettino/c8bf5062ef99993ce32514807ffae849

Ответы [ 2 ]

1 голос
/ 24 января 2020

Необходимо, чтобы каждый возвращаемый тип создателя действия был помечен as const, чтобы TS мог различать ваши действия в операторе switch редуктора.

В setTotals это константное утверждение, по-видимому, отсутствует - по крайней мере, предоставленный код снова работает на детской площадке после его добавления.

Вы можете создать универсальный c создатель действий, чтобы сделать его более масштабируемым, и пропустить as const:

function createAction<T extends string, U, K extends string>(type: T, key: K, payload: U) {
  return ({
    type,
    [key]: payload
  }) as { type: T; } & { [P in K]: U }
  // need to cast, so TS doesn't return a widened index signature type
}

export function setTotals(totals: CartTotal) {
  return createAction(SET_CART_TOTALS, "totals", totals)
}
// same with the other functions

Пример кода на игровой площадке

1 голос
/ 24 января 2020

Используя способ, которым вы реализовали CartActions, вы всегда должны назначать ему тип каждого действия.

Например, вы должны изменить:

case REMOVE_CART_ITEM:
  return {
    ...state,
    cart: {
      ...action.cart
    }
  }

на это:

case REMOVE_CART_ITEM:
  return {
    ...state,
    cart: {
      ...action.cart
    }
  } as ReturnType<typeof removeCartItem>

или вы можете изменить CartActions, поэтому введите действовать как разделитель:

const enum ActionTypes {
  SET_CART_ITEMS,
  SET_CART_TOTALS,
  ADD_CART_ITEM,
  REMOVE_CART_ITEM,
  SET_CART_LOADING
}



type CartActions =
  | {
      type:
        | ActionTypes.SET_CART_ITEMS
        | ActionTypes.ADD_CART_ITEM
        | ActionTypes.REMOVE_CART_ITEM;
      cart: Cart;
    }
  | {
      type: ActionTypes.SET_CART_TOTALS;
      totals: CartTotal;
    }
  | {
      type: ActionTypes.SET_CART_LOADING;
      loading: boolean;
    };

export function setCart(cart: Cart): CartActions {
  return {
    type: ActionTypes.SET_CART_ITEMS,
    cart
  };
}

export function setTotals(totals: CartTotal): CartActions {
  return {
    type: ActionTypes.SET_CART_TOTALS,
    totals
  };
}

export function addCartItem(cart: Cart): CartActions {
  return {
    type: ActionTypes.ADD_CART_ITEM,
    cart
  };
}

export function removeCartItem(cart: Cart): CartActions {
  return {
    type: ActionTypes.REMOVE_CART_ITEM,
    cart
  };
}

export function toggleCartLoading(loading: boolean): CartActions {
  return {
    type: ActionTypes.SET_CART_LOADING,
    loading
  };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...