所以我在一个todomvc中得到了这个经典的switch case redux reducer,我想让它功能化,但似乎不能让我的头围绕ts类型。
Switch case在模式匹配方面非常有效,并且可以通过类型来缩小动作区分的并集。但是我似乎不知道如何用函数方法来传递缩小的动作,在这种方法中,对象文字的键应该进行类型缩小。
到目前为止,我得到的是所有函数的联合类型和一些ts错误。我真的很感激在这件事上的任何帮助,以获得一个更好的想法如何使用严格类型与ts。
import { action as actionCreator } from 'typesafe-actions';
import uuid from 'uuid';
import { ITodo } from 'types/models';
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_ALL = 'todos/TOGGLE_ALL';
const REMOVE_TODO = 'todos/REMOVE_TODO';
export const addTodo = (title: string) => actionCreator(ADD_TODO, { title });
export const removeTodo = (id: string) => actionCreator(REMOVE_TODO, { id });
export const toggleAll = (checked: boolean) =>
actionCreator(TOGGLE_ALL, { checked });
type TodosAction =
| ReturnType<typeof addTodo>
| ReturnType<typeof removeTodo>
| ReturnType<typeof toggleAll>;
type TodosState = ReadonlyArray<ITodo>;
// no idea what typings should be
const switchCase = <C>(cases: C) => <D extends (...args: any[]) => any>(
defaultCase: D
) => <K extends keyof C>(key: K): C[K] | D => {
return Object.prototype.hasOwnProperty(key) ? cases[key] : defaultCase;
};
export default function(
state: TodosState = [],
action: TodosAction
): TodosState {
// union type of 4 functions
const reducer = switchCase({
// (parameter) payload: any
// How do I get types for these?
[ADD_TODO]: payload => [
...state,
{
completed: false,
id: uuid.v4(),
title: payload.title,
},
],
[REMOVE_TODO]: payload => state.filter(todo => todo.id !== payload.id),
[TOGGLE_ALL]: payload =>
state.map(todo => ({
...todo,
completed: payload.checked,
})),
})(() => state)(action.type);
// [ts] Cannot invoke an expression whose type lacks a call signature. Type
// '((payload: any) => { completed: boolean; id: string; title: any; }[]) |
// ((payload: any) => ITodo[...' has no compatible call signatures.
return reducer(action.payload);
}
2条答案
按热度按时间f87krz0w1#
一个有趣的类型问题。第一个关于有效载荷类型的问题我们可以通过传入所有可能的操作(
TodosAction
)来解决,并要求switchCase
的参数必须是一个Map类型,该类型将包含联合体中所有types
的属性,对于每一个类型,我们可以使用Extract
条件类型来提取有效载荷类型。问题的第二部分是由以下事实引起的:当使用键对类型进行索引时,(即联合类型本身),您将从该类型中获得所有可能值的联合。在本例中,这将是函数的联合,该类型脚本不认为是可调用的。为了解决这个问题,我们可以更改内部函数的公共签名,以返回一个函数,该函数将所有有效负载的并集作为参数,而不是每个函数都有一个有效负载。
结果如下所示:
Playground链接
yeotifhr2#
这并不是对最初问题的准确回答,但它是相邻的,可能会帮助一些人在谷歌上遇到这个问题。
我正在尝试将
useReducer
与TypeScript一起使用。以下是我的设置:我希望所有的东西都是类型安全的,我希望有动作创建器函数,我不希望必须多次定义我的动作/负载类型。
对我来说,最重要的是
as const
。没有它,TypeScript会认为setLoading
函数的返回类型是string
,而不是字符串文字setLoading
。我猜是因为对象是可变的吧?总之,as const
会生成const setLoading: (value: boolean) => { type: "setLoading"; payload: boolean; }
类型,这会使所有类型都正常工作。