typesafe-actions 简易实现

要实现的方法

在项目中使用了 typesafe-actions,我最常用的几个方法有三个

  • createAction
  • createStandardAction
  • getType

createAction

使用

1
2
const fetchList = createAction(Types.FETCH_LIST);
dispatch(fetchList());

实现

1
2
3
4
5
6
7
8
// common.ts
export function createAction<T extends string>(type: T) {
return function() {
return {
type
};
};
}

createStandardAction

使用

1
2
const fetchList = createStandardAction(Types.FETCH_LIST)<string>();
dispatch(fetchList("name"));

这里为何要如此调用?如果把 payload 的泛型写在第一个函数上,那第一个函数就需要两个泛型了,type 的泛型每次都需要显式的写出来,很麻烦,这里利用多返回一层函数把 payload 的泛型写在第二个函数上,会隐去 type 的泛型声明

1
2
3
4
// 上边的写法 编译器 帮我们确定了 type 类型
const fetchList = createStandardAction<Types.FETCH_LIST>(Types.FETCH_LIST)<
string
>();

实现

1
2
3
4
5
6
7
8
9
10
11
// common.ts
export function createStandardAction<T extends string>(type: T) {
return function<P>() {
return function(arg: P): { type: T; payload: P } {
return {
type,
payload: arg
};
};
};
}

getType

使用

1
2
3
4
switch(action.type){
case getType(fetchList):
...
}

使用 getType 方法,可以避免多出引用 type 常量

实现

1
2
3
4
5
// common.ts
export type ActionCreator<T extends string> = (...args: any[]) => { type: T };
export function getType<T extends string>(action: ActionCreator<T>) {
return action().type;
}

这个实刚好能满足我们的需求,但实现略丑陋(捂脸)

ActionType in reducer

在写 reducer 的时候,我们需要获取和这个 reducer 有关的所有 action 类型,如下边代码type AllActions = ActionType<typeof actions>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// reducer.ts
import * as actions from "./actions";
import ActionType from "./common";

export type AllActions = ActionType<typeof actions>;

const reducer: Reducer<AllState, AllActions> = (
state = initialState,
action: AllActions
) => {
switch (action.type) {
case getType(actions.fetchList):
return {
...state
};

default:
return state;
}
};

实现

1
2
3
4
5
6
7
8
9
10
11
// common.ts

export type ActionResult<T> = T extends (...args: any[]) => any
? ReturnType<T>
: never;

type ActionCreatorMap<T> = { [K in keyof T]: ActionResult<T[K]> };

export type ActionType<T> = T extends object
? ActionCreatorMap<T>[keyof T]
: ActionResult<T>;

ActionType 支持 object 类型或函数类型

1
2
3
type AllActions = ActionType<typeof actions>;
// AllActions的形式类似于
// {type: 'TYPE1', payload: string} | {type: 'TYPE2'}