派生类型的函数关联数组

时间:2018-03-29 20:42:20

标签: typescript

我希望函数的调用者提供一个关联的函数数组。 我的函数将返回一个新的关联函数数组,它们具有相同的键,返回类型相同,但函数将采用与传递给函数的映射函数不同的参数。

我无法弄清楚如何创建此函数的返回类型。

到目前为止,我的尝试是:

type FunctionMap<A> = {
    [functionName: string]: <R>(a: A) => R
}

type B = {};
const b: B = {};

const FunctionMapArg: FunctionMap<B> = {
    getA: b => 1,
    getB: b => "two"
};

type TypeOfFunctionMapArg = typeof FunctionMapArg;


type ReturnedFunctionMap<T extends TypeOfFunctionMapArg> = {
    [P in keyof T]: () => ???; // using Typescript 2.6
//    [P in keyof T]: () => ReturnType<T[P]); // using Typescript 2.8
}

然而,这在第一步失败了 - 我甚至无法宣布FunctionMapArg常数。我从编译器中收到以下错误:

Type '{ getA: <R>(a: any) => number; getB: <R>(a: any) => string; }' is not assignable to type 'FunctionMap<any>'.
Property 'getA' is incompatible with index signature.
Type '<R>(a: any) => number' is not assignable to type '<R>(a: any) => R'.
Type 'number' is not assignable to type 'R'.

请有人请我指明正确的方向吗?理想情况下,我正在寻找适用于Typescript 2.6的解决方案。

1 个答案:

答案 0 :(得分:2)

我不确定你想要输入和输出函数的参数是什么,所以这是猜测。主要思想是使用mapped typesinference from mapped types来表示您想要实现的转换。 (这两个功能都应该适用于TypeScript 2.6。)例如,假设您的输入函数如下所示:

type B = {
  // input function argument type here
};

const functionMapArg = {
  getA: (b: B) => 1,
  getB: (b: B) => "two"
};

declare const b: B;
const gotA = functionMapArg.getA(b); // number
const gotB = functionMapArg.getB(b); // string

然后,这是改变functionMapArg的一种方式:

type Functionize<T, A> = { [K in keyof T]: (a: A) => T[K] };
type C = {
  // output function argument type here
};
declare function alterFunctions<T>(fs: Functionize<T, B>): Functionize<T, C>;

Functionize<T, A>采用常规对象类型T并生成一个映射类型,其键KT的键相同,其值是来自{{的函数1}}到AT[K]alterFunctions()作为输入(例如Functionize<T, B>),并生成functionMapArg作为输出...其中TypeScript编译器推断类型Functionize<T, C>为了你。让我们看看它是否有效:

T

因此const alteredFunctions = alterFunctions(functionMapArg); declare const c: C; const gotAnotherA = alteredFunctions.getA(c); // number const gotAnotherB = alteredFunctions.getB(c); // string alteredFunctions类似,但其方法采用类型为functionMapArg的参数,而不是C类型的参数。这就是你要找的东西吗?

希望有所帮助;祝你好运!

更新:如果你想避免为B中的每个函数编写参数类型,你可以创建一个辅助函数,它需要输入类型functionMapArg并返回输入不变,如下所示:

Functionize<any, B>

这样编译器就会推断出参数类型:

function asFunctionsOfB<F extends Functionize<any, B>>(fs: F): F {
  return fs;
}

希望有所帮助。