具有对象文字和Typescript

时间:2018-07-29 15:59:13

标签: typescript redux functional-programming switch-statement

所以我在todomvc中有这个经典的开关盒redux减速器,我想使其功能化,但似乎无法将ts的内容包起来。

开关盒非常适合模式匹配,并缩小按类型区分的联合动作。但是我似乎不知道如何使用一种功能性方法来传递缩小的动作,在该方法中对象文字的键应该进行类型缩小。

到目前为止,我得到的是所有函数的联合类型以及一些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);
}

1 个答案:

答案 0 :(得分:2)

一个有趣的打字问题。关于有效负载类型的第一个问题,我们可以通过传递所有可能的动作( * project | - src | | - app (with app files like app.modules.ts) | | - tsconfig.app.json | - tsconfig.json )来解决,并要求TodosAction的参数必须是一个映射类型,该类型将包含所有{{ 1}}中的联合,对于每种类型,我们可以使用switchCase条件类型来提取有效载荷类型。

问题的第二部分是由于当您使用键索引类型(本身是并集类型)时,会从该类型中获得所有可能值的并集。在这种情况下,这将是函数的并集,而打字稿则认为不能调用。为了解决这个问题,我们可以更改内部函数的公共签名,以返回一个将所有有效载荷的并集而不是每个都带有有效载荷的函数并集作为参数的函数。

结果看起来像这样:

types

Playground link