打字稿:更改函数类型,使其 returns 新值
Typescript: change function type so that it returns new value
基本上,我想要这样的东西:
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
}
编辑
自从回答了原始问题后,typescript 改进了这个问题的可能解决方案。添加 Tuples in rest parameters and spread expressions 我们现在不需要所有重载:
type ReplaceReturnType<T extends (...a: any) => any, TNewReturn> = (...a: Parameters<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, but for now this 提供可行的解决方案。 (将其张贴在这里,因为那里的类型用作解决不同问题的一部分)。
基本思想是我们将提取参数类型并使用新的 return 类型重组函数签名。这种方法有几个缺点:
- 不保留参数名称
- 可选参数处理不好
- 仅适用于特定数量的参数(但可以根据需要添加更多)
可能还有其他问题,但根据您的用例,在类型系统解决此用例之前,这可能是一个足够好的解决方案。
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);
基本上,我想要这样的东西:
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
}
编辑
自从回答了原始问题后,typescript 改进了这个问题的可能解决方案。添加 Tuples in rest parameters and spread expressions 我们现在不需要所有重载:
type ReplaceReturnType<T extends (...a: any) => any, TNewReturn> = (...a: Parameters<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, but for now this
基本思想是我们将提取参数类型并使用新的 return 类型重组函数签名。这种方法有几个缺点:
- 不保留参数名称
- 可选参数处理不好
- 仅适用于特定数量的参数(但可以根据需要添加更多)
可能还有其他问题,但根据您的用例,在类型系统解决此用例之前,这可能是一个足够好的解决方案。
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);