这是我想为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
的东西相交。
答案 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"]; }
。