Typescript:更改函数类型,以便返回新值

时间:2018-04-24 22:33:56

标签: typescript recompose

基本上,我想要这样的东西:

export type ReturnValueMapper<Func extends (...args: Args[] /* impossible */ ) => any, ReturnValue> = (...args: Args[]) => ReturnValue;

我几乎可以肯定这是不可能的,但我还没有找到确切的确认。

用例正在改进recompose's withStateHandlers的类型,允许定义状态更新器,如下所示:

interface StateUpdaters {
    update(field: string): void; // I don't want to specify Partial<State> here 
}

1 个答案:

答案 0 :(得分:9)

修改

由于原始问题得到解答,打字稿已经改进了这个问题的可能解决方案。添加Tuples in rest parameters and spread expressions后,我们现在不需要进行所有重载:

type ArgumentTypes<T> = T extends (... args: infer U ) => infer R ? U: never;
type ReplaceReturnType<T, TNewReturn> = (...a: ArgumentTypes<T>) => TNewReturn;

这不仅缩短了,而且解决了许多问题

  • 可选参数保持可选
  • 保留参数名称
  • 适用于任意数量的论点

示例:

type WithOptional = ReplaceReturnType<(n?: number)=> string, Promise<string>>;
let x!: WithOptional; // Typed as (n?: number) => Promise<string>
x() // Valid
x(1); //Ok

<强> 原始

要获得一个好的解决方案,您需要variadic types,但目前这个answer提供了一个可行的解决方案。 (在此处将其作为类型发布,作为解决其他问题的一部分)。

基本思想是我们将提取参数类型并使用新的返回类型重新组合函数签名。这种方法有几个缺点:

  1. 不保留参数名称
  2. 无法妥善处理可选参数
  3. 仅适用于特定数量的参数(但可根据需要添加更多参数)
  4. 可能存在其他问题,但根据您的用例,这可能是一个足够好的解决方案,直到类型系统解决此用例。

    type IsValidArg<T> = T extends object ? keyof T extends never ? false : true : true;
    type ReplaceReturnType<T, TNewReturn> = T extends (a: infer A, b: infer B, c: infer C, d: infer D, e: infer E, f: infer F, g: infer G, h: infer H, i: infer I, j: infer J) => infer R ? (
        IsValidArg<J> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => TNewReturn :
        IsValidArg<I> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => TNewReturn :
        IsValidArg<H> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => TNewReturn :
        IsValidArg<G> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => TNewReturn :
        IsValidArg<F> extends true ? (a: A, b: B, c: C, d: D, e: E, f: F) => TNewReturn :
        IsValidArg<E> extends true ? (a: A, b: B, c: C, d: D, e: E) => TNewReturn :
        IsValidArg<D> extends true ? (a: A, b: B, c: C, d: D) => TNewReturn :
        IsValidArg<C> extends true ? (a: A, b: B, c: C) => TNewReturn :
        IsValidArg<B> extends true ? (a: A, b: B) => TNewReturn :
        IsValidArg<A> extends true ? (a: A) => TNewReturn :
        () => TNewReturn
    ) : never
    

    与可选参数一起使用时的问题是可选参数变为必需(并且为type A | undefined):

    type WithOptional = ReplaceReturnType<(n?: number)=> string, Promise<string>>;
    
    let x!: WithOptional;
    x(); //invalid
    x(undefined);
    x(1);