如何键入部分应用其他功能的功能?

时间:2019-02-13 07:57:07

标签: typescript

这是我想为JsDoc提供类型签名的javascript函数:

function provideExtra(f, extra) {
  return (props, ...args) => f({ ...props, extra }, ...args)
}

我认为应该是这样,但是我做错了:

/**
 * @param {(props: Props, ...args: Args) => Result} f
 * @param {Extra} extra
 * @template Extra
 * @template {{ extra: Extra }} Props
 * @template {Array} Args
 * @template Result
 * @returns {(props: Omit<Props, 'extra'>, ...args: Args) => Result}
 */

我将Omit定义为type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

如果无法在JsDoc中完成此操作,但也可以在.d.ts文件中完成。


更新

可从外部使用的版本:

/**
 * @template {Object} P
 * @template {Array} A
 * @template R
 * @param {(props: P, ...args: A) => R} f
 * @param {P['extra']} extra
 * @returns {(props: Omit<P, 'extra'>, ...args: A) => R}
 */
export function provideExtra(f, extra) {
  return (props, ...args) => f(Object.assign({}, props, { extra }), ...args)
}

但这会为Object.assign产生错误:

  

类型Pick<P, Exclude<keyof P, "extra">> & { extra: P["extra"]; }的参数不能分配给类型'P'的参数。 [2345]

在我幼稚的头脑中,这种类型会导致P;省略extra并与具有正确类型的extra的东西相交。

1 个答案:

答案 0 :(得分:1)

怎么样

apiMock.fetchAllComments.mockClear();  // clear the mock
apiMock.filterComments.mockClear();  // clear the mock

component.instance().componentDidMount();

expect(spySetComments).toHaveBeenCalledTimes(1);  // SUCCESS
expect(apiMock.fetchAllComments).toHaveBeenCalledTimes(1);  // SUCCESS
expect(apiMock.filterComments).toHaveBeenCalledTimes(1);  // SUCCESS

UPD。是的,您是对的:TypeScript无法按预期推断function provideExtra<Props,Extra,Args extends any[],Result>( f: (p: Props & {extra: Extra}, ...args: Args) => Result, extra: Extra ) { return (props: Props, ...args: Args) => f({ ...props, extra }, ...args) } 。您必须这样称呼它:

Props

通过一些类型推断,我能够减少类型参数的数量:

const f = (props: {prefix: string, extra: string}, suffix: string) => props.prefix + props.extra + suffix;
const g = provideExtra<{prefix: string},string,[string],string>(f,"mid");

但是除非有更简单的解决方案,否则我可能只添加类型断言,因为type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; type FirstArg<F> = F extends (p: infer U, ...args: any[]) => any ? U : never; type Extra<F> = FirstArg<F> extends {extra: infer U} ? U : never; type OtherProps<F> = Omit<FirstArg<F>,"extra" & keyof FirstArg<F>> & { extra?: never}; type Rest<F> = F extends (p: any, ...args: infer V) => any ? V : never; function provideExtra<F extends (...args: any[]) => any>( f: (p: OtherProps<F> & {extra: Extra<F>}, ...args: Rest<F>) => ReturnType<F>, extra: Extra<F> ) { return (props: OtherProps<F>, ...args: Rest<F>) => f({ ...props, extra }, ...args) } const f = (props: {prefix: string, extra: string}, suffix: string) => props.prefix + props.extra + suffix; const g = provideExtra<typeof f>(f,"mid"); const t = g({prefix: "prefix"}, "suffix"); 显然是Omit<P, "extra"> & { extra: P["extra"]; }