javascript - ประเภทการส่งค่ากลับของ Redux actions ใน typescript ไม่ทำงาน
ดังนั้นพื้นฐานแล้วฉันกำลังพยายามส่งค่าประเภทสำหรับชุดฟังก์ชันและสามารถจับคู่นั้นในรีดิวเซอร์ของ Redux ของฉันได้
นี่คือความพยายามของฉัน:
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;
}
สิ่งนี้ใช้ไม่ได้เลย ข้อผิดพลาดที่ฉันได้รับเกิดขึ้นในสวิตช์ของ reducer โดยบอกว่า:
"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
คำตอบ #1
จำเป็นที่ชนิดการคืนค่าของตัวสร้างแอคชันแต่ละตัวจะต้องถูกระบุด้วย as const เพื่อที่ TypeScript จะสามารถแยกความแตกต่างของแอคชันของคุณในคำสั่ง switch ของ reducer ได้
ใน setTotals ดูเหมือนว่าจะขาดการยืนยัน const ไป - อย่างน้อยโค้ดที่ให้มาทำงานได้อีกครั้งใน playground หลังจากที่เพิ่มมันเข้าไปแล้ว
คุณสามารถสร้างตัวสร้างแอ็กชันทั่วไปเพื่อทำให้มันสามารถขยายได้มากขึ้นและละเว้น 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
ตัวอย่างโค้ดใน Playground
คำตอบ #2
ด้วยวิธีที่คุณนำ CartActions ไปใช้งาน คุณควรกำหนดประเภทของแต่ละการกระทำให้กับมันเสมอ
ตัวอย่างเช่น คุณควรเปลี่ยน:
case REMOVE_CART_ITEM:
return {
...state,
cart: {
...action.cart
}
}
ไปยังนี้:
case REMOVE_CART_ITEM:
return {
...state,
cart: {
...action.cart
}
} as ReturnType<typeof removeCartItem>
หรือคุณสามารถแก้ไข CartActions ของคุณเพื่อให้ type ทำหน้าที่เป็นตัวคั่น:
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
};
}
