【问题标题】:Omit empty array from generic function paramater call in typescript在打字稿中从通用函数参数调用中省略空数组
【发布时间】:2022-10-13 01:04:29
【问题描述】:

F 没有接收到参数时,我正在寻找一种不为泛型函数Parameter<F> 类型参数提供空数组的方法。 以下工作示例显示了当前状态

type A<F extends (...args: any[]) => any> = {
    shouldPrintHello: boolean;
    params: Parameters<F>;
};

const wrappingFunction = <F extends (...args: any[]) => any>(sentFunction: F, defaultParams: A<F>) => {
    const innterFunction = (...args: Parameters<F>) => {
        if (defaultParams.shouldPrintHello) console.log("hello");
        sentFunction(args);
        return;
    };

    const defaultValue = sentFunction(defaultParams);
    return innterFunction;
};

const f1 = wrappingFunction(
    (arg0: string) => {
        return;
    },
    { shouldPrintHello: true, params: ["defaultString"] }
);

const f2 = wrappingFunction(
    () => {
        return;
    },
    { shouldPrintHello: true, params: [] }
);

f1("a string");
f2();

所需的(伪)代码更改:

type A<F extends (...args: any[]) => any> = {
    shouldPrintHello: boolean;
    params: Parameters<F> === [] ? undefined : Parameters<F>;
};

const f2 = wrappingFunction(
    () => {
        return;
    },
    { shouldPrintHello: true }
);

f2();

【问题讨论】:

  • 您检查过extends 关键字吗?
  • 是的,但遗憾的是我不明白它在这里有什么用处
  • 如何?它的功能与平等非常相似。虽然不是“平等”,而是更多的是“<:”,但在这里仍然有效。
  • this approach 是否满足您的需求?如果是这样,我可以写一个答案;如果没有,我错过了什么? (请在您的评论中说@jcalz 以通知我)
  • @jcalz 谢谢,但这种方法对我不起作用。我正在尝试按如下方式实现它但没有成功:link

标签: typescript generics


【解决方案1】:

不要害怕使用extends 来检查“平等”:

type A<F extends (...args: any[]) => any> = {
    shouldPrintHello: boolean;
    params: Parameters<F> extends [] ? undefined : Parameters<F>;
};

或者,您可以检查长度:

params: Parameters<F>["length"] extends 0 ? undefined : Parameters<F>;

【讨论】:

  • 谢谢,但在应用您的建议后,我仍然必须使用{ shouldPrintHello: true, params: undefined }
【解决方案2】:

没有内置的方式来表示一个属性是可选的,当且仅当某些条件保持它的值时,所以如果你想要一个这样的类型,你必须自己将它写成conditional type

type OptionalParamsIfAllowedToBeEmpty<P> =
  [] extends P ? { params?: P } : { params: P }

然后你可以 intersect 将它添加到你的类型定义的其余部分:

type A<F extends (...args: any[]) => any> = {
  shouldPrintHello: boolean;
} & OptionalParamsIfAllowedToBeEmpty<Parameters<F>>;

declare const wrappingFunction: <F extends (...args: any[]) => any>(
  sentFunction: F,
  defaultParams: A<F>) => (...args: Parameters<F>) => void

让我们测试一下。首先,让我们确保它对于具有至少一个必需参数的函数的行为符合预期:

wrappingFunction(
  (arg0: string) => {
    return;
  },
  { shouldPrintHello: true, params: ["defaultString"] }
);    

wrappingFunction(
  (arg0: string) => {
    return;
  },
  { shouldPrintHello: true } // error! missing params
);

看起来不错,params 不是可选的。然后让我们测试一下没有任何参数的函数:

wrappingFunction(
  () => {
    return;
  },
  { shouldPrintHello: true }
);

wrappingFunction(
  () => {
    return;
  },
  { shouldPrintHello: true, params: [] } // okay
);

wrappingFunction(
  () => {
    return;
  },
  { shouldPrintHello: true, params: undefined } // okay
);

wrappingFunction(
  () => {
    return;
  },
  { shouldPrintHello: true, params: ["defaultString"] } // error
);

看起来也不错;你可以省略params,或传入undefined 或一个空数组[],但它不会让你传入错误的参数。最后,让我们看看它是如何处理带有可选参数的函数的:

function f(x?: string) { }
wrappingFunction(f, { shouldPrintHello: false }) // okay
wrappingFunction(f, { shouldPrintHello: false, params: ["abc"] }) // okay

这也是你想要的,我想。既然你可以打电话给f(),你不应该必需的wrappingFunction 中传入params,但既然你也可以调用f("abc"),你应该是允许["abc"] 传递params。这是OptionalParamsIfAllowedToBeEmpty&lt;P&gt; 中的[] extends P 检查与看似相似的P extends [] 检查之间的重要区别;如果P[x?: string],则[] extends [x?: string] 为真,但[x?: string] extends [] 为假。

Playground link to code

【讨论】:

    猜你喜欢
    • 2022-12-01
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 2017-11-23
    • 2018-03-15
    • 1970-01-01
    • 2020-04-24
    • 1970-01-01
    相关资源
    最近更新 更多