Typescript 如何键入部分应用另一个函数的函数?

Typescript 如何键入部分应用另一个函数的函数?,typescript,Typescript,这是我想为以下对象提供一个带有类型签名的JsDoc的javascript函数: function provideExtra(f, extra) { return (props, ...args) => f({ ...props, extra }, ...args) } 我认为应该是这样的,但我不能正确理解: /** * @param {(props: Props, ...args: Args) => Result} f * @param {Extra} extra * @

这是我想为以下对象提供一个带有类型签名的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}
 */
但是,这会为
对象生成错误。分配

类型为
Pick&{extra:p[“extra”];}
的参数不能分配给类型为“p”的参数。[2345]

在我天真的头脑中,这种类型会导致
p
;省略
extra
并将其与具有正确类型的
extra
的内容相交。

如何

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)
}
通过某种类型推断,我能够减少类型参数的数量:

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");
类型省略=拾取;
输入FirstArg=F扩展(p:inferu,…args:any[])=>any?U:从来没有;
type Extra=FirstArg扩展{Extra:inferu}?U:从来没有;
键入OtherProps=Omit&{extra?:never};
类型Rest=F扩展(p:any,…args:inferv)=>any?V:从来没有;
函数provideExtra any>(
f:(p:OtherProps&{extra:extra},…args:Rest)=>ReturnType,
额外的:额外的
) {
return(props:OtherProps,…args:Rest)=>f({…props,extra},…args)
}
常量f=(props:{prefix:string,extra:string},后缀:string)=>props.prefix+props.extra+suffix;
常数g=提供额外(f,“mid”);
常数t=g({前缀:“前缀”},“后缀”);

但是,除非有更简单的解决方案,否则我可能只会添加一个类型断言,因为
省略&{extra:p[“extra”];}
显然是
p

现在生成的函数需要与
f
相同的道具,它不需要
额外的
道具。是的,对不起<代码>道具
并不像人们希望的那样被推断出来。我更新了答案。
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");