前言
目前 TS 官方 API 还不支持获取函数返回值类型,但是对于函数式编程流行的当今,这个功能非常的重要,比如我们希望能在使用 redux-thunk 中 getState 或者 mapStateToProps 中 state 时 IDE 提示 state 类型,这时就需要获取 reducer 函数的返回值类型,并且进行联合导出供我们使用。
前置知识
以上几点都能在 TS 文档中找到非常清晰简洁的解释和例子,这里就不花篇幅解释了。
核心代码
// 声明一个泛型类型别名,返回值与泛型类型相同,入参类型不限制。
type Reverse<T> = (arg: any) => T;
// 声明一个泛型方法,入参arg继承泛型约束,返回空对象并断言其类型为T
function returnResultType<T>(arg: Reverse<T>): T {
return {} as T;
}
// 调用returnResultType,传入方法 (arg: any) => 3,获得result返回值
const result = returnResultType((arg: any) => 3);
// 获取result类型并重名为ResultType
type ResultType = typeof result;
代码分析
returnResultType((arg:any)=>3);
调用 returnResultType 时,由于没有显示声明泛型类型,所以 TS 只能通过入参来进行类型推论,接着往下面走:
type Reverse<T> = (arg: any) => T;
由于入参的类型为 Reverse ,通过入参返回值是 3 可以推断出:
type Reverse<number> = (arg: any) => number;
由于 Reverse 的 T 是根据 returnResultType 传入的,所以同理得出:
function returnResultType<number>(arg: Reverse<number>): number {
return {} as number;
}
由于返回值已经进行类型断言为 number。所以在 typeof result 时,可以得出 number 类型。
该方法确实比较绕,因为存在多个泛型 T 的来回推论和反推论。
~~~
结合 Redux 应用
接下来我们通过 reducer 函数来应用一下:
- 首先编写两个简单的 reducer:userReducer 和 loginReducer
/**
* userReducer
*/
const initUserState = {
name: ''
}
const userReducer = (state = initUserState, action: any) => {
switch (action.type) {
case 'setName':
return {
name: 'Larry',
...state
};
default:
return state;
}
}
/**
* loginReducer
*/
const initLoginState = {
token: ''
}
const loginReducer = (state = initLoginState, action: any) => {
switch (action.type) {
case 'login':
return {
token: 'token',
...state
};
default:
return state;
}
}
- 在 store 中
const reducers = combineReducers({
userReducer,
loginReducer
});
type Reverse<T> = (state: any, action:any) => T;
function returnResultType<T>(arg: Reverse<T>): T {
return {} as T;
}
const GlobalState = returnResultType(reducers);
type GlobalStateType = typeof GlobalState;
此时的 GlobalStateType 就是我们需要的所有 reducer 函数返回的对象类型。
最后得到的类型
最后,导出 GlobalStateType,在我们 mapStateToProps 中使用时就能轻松得到类型: