在循环中调用时,函数返回的类型无法正确解析

时间:2019-04-27 15:03:21

标签: javascript node.js typescript

我用两个函数创建了一个简单的映射,这些函数带有一个'foo:string'参数,并实现了直接返回的各种函数:

import { mapValues } from 'lodash';

const fun1 = (foo: string) => (name: string, surname: string) => {};
const fun2 = (foo: string) => (age: number) => {};

interface Actions {
  fun1: typeof fun1;
  fun2: typeof fun2;
}

const actions: Actions = { fun1, fun2 };

const mappedActions = mapValues(actions, action => action('bar'));

mappedActions.fun1(1);

使用mapValues,我遍历这些函数,并使用一些公共参数调用它们。我期望的是mappedActions映射中分配的半调用函数的映射,但是类型仍然存在问题。

fun1不能解析为具有(name: string, surname: string)参数,但仍是顶层参数的函数。

我应该如何构成才能使TypeScript正确解析类型?

enter image description here

2 个答案:

答案 0 :(得分:2)

我将您的代码段复制到了CodeSandbox,并分析了Lodash的功能mapValues(),我认为mapValues()的类型与您的目的不符。

mapValues<T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>): { [P in keyof T]: TResult };

如您所见,函数mapValues接受一个对象(T extends object),并为此对象的每个键分配TResult,这样:

mapValues<Actions, ((name: string, surname: string) => void) | ((age: number) => void)>(obj: Actions, callback: ObjectIterator<Actions, ((name: string, surname: string) => void) | ((age: number) => void)>): {

我尝试将lodash(尤其是 lodash / fp )与TypeScript结合使用,我可以说并非所有功能都能完美运行,也很难为所有可能性创建通用类型

答案 1 :(得分:1)

我想我找到了一种正确解析类型的方法:

import { mapValues } from 'lodash';

const fun1 = (foo: string) => (name: string, surname: string) => {};
const fun2 = (foo: string) => (age: number) => {};

type FunctionDictionary = { [id: string]: ((...args: any[]) => any) };

interface Actions extends FunctionDictionary {
  fun1: typeof fun1;
  fun2: typeof fun2;
}

const actions: Actions = { fun1, fun2 };

type ReturnTypeDict<T> = T extends { [id: string]: ((...args: any[]) => any) } ? {
  [P in keyof T]: ReturnType<T[P]>;
} : never;

const map: (actions: Actions) =>  ReturnTypeDict<Actions> = actions => {
  return mapValues(actions, action => action('bar')) as ReturnTypeDict<Actions>;
}

const mappedActions = map(actions);

mappedActions.fun1(1);

此处的键是ReturnType条件类型。为了使用它,您必须创建自己的条件类型:

type ReturnTypeDict<T> = T extends { [id: string]: ((...args: any[]) => any) } ? {
  [P in keyof T]: ReturnType<T[P]>;
} : never;

现在您必须明确地说您的接口扩展了所需的字典类型:

type FunctionDictionary = { [id: string]: ((...args: any[]) => any) };

interface Actions extends FunctionDictionary {
  fun1: typeof fun1;
  fun2: typeof fun2;
}

然后创建一个可以正确映射数据的函数:

const map: (actions: Actions) =>  ReturnTypeDict<Actions> = actions => {
  return mapValues(actions, action => action('bar')) as ReturnTypeDict<Actions>;
}