【问题标题】:conditional function arguments in typescript打字稿中的条件函数参数
【发布时间】:2021-10-03 12:02:11
【问题描述】:

是否可以基于第一个参数类型有一个分生孢子所需的参数类型:

type ConditionalRequiredArg<T, P> = T extends string ? P | undefined : P;

function func<T, P>(_arg1: string | number, _arg2: ConditionalRequiredArg<T, P>) {}

func('foo'); // Error: Expected 2 arguments, but got 1.

理论上,上述函数不应该需要第二个参数,但它确实需要!

编辑:我知道“?”对于可选参数类型,但我想有条件地利用编译器错误和建议。

【问题讨论】:

  • 为什么要定义一个可选类型并期望函数的可选参数行为?您可以通过放置一个 ?在参数的末尾如下: function func(_arg1: string | number, _arg2?: ConditionalRequiredArg)
  • 更多的是好奇和尝试的可能性。我知道我可以使用“?”使其成为可选的,但我希望它是有条件的,以便用户知道何时需要第二个参数。

标签: typescript function-parameter conditional-types


【解决方案1】:

您始终可以使用signature overloading 来筛选用户,避免直接使用实现签名:

function func<P>(_arg1: string, _arg2?: P)
function func<P>(_arg1: number, _arg2: P)
function func<P>(_arg1: string | number, _arg2?: P) { }

此代码强制用户选择要使用的第一个签名或第二个签名,而不是实现的第三个签名。

func('foo', 1); // success
func('foo'); // success
func(1, 1); // success
func(1); // Error: Argument of type 'number' is not assignable to parameter of type 'string'

【讨论】:

    【解决方案2】:

    我认为你混淆了两种不同的东西。

    func<T, P>(_arg1: string | number, _arg2: ConditionalRequiredArg<T, P>)
    

    表示该函数需要 2 个参数,其中第二个参数的类型可能是 undefined,意思是:

    _arg2 = undefined,其中字段_arg2 已声明。

    但您希望不声明该字段。

    _arg2 = undefined 不等于说:

    func<T, P>(_arg1: string | number, undefined)
    

    对于这个用例,您可以使用 ?如下:

    func<T, P>(_arg1: string | number, _arg2?: ConditionalRequiredArg<T, P>)
    

    编辑:

    类型和参数是两个不同的东西。类型定义值的类型,而参数是字段。

    虽然这不是一个好习惯,但您也可以使用 undefined 手动初始化字段,如下所示:

    func<T, P>(_arg1: string | number, _arg2: string = undefined)
    

    但这到底和_arg2?一样

    undefined 类型就像说“该字段不包含任何内容”或更好地说“该字段包含未定义”,而字段 undefined 是“该字段不存在”

    【讨论】:

    • 感谢我知道“?”的建议对于可选参数类型,但我希望使其有条件并利用编译​​器错误和建议。
    【解决方案3】:

    定义函数的第二个参数的第一个解决方案是 使用? 运算符将其标记为可选,并具有以下内容:

    // ...
    function func<T, P>(_arg1: string | number, _arg2?: ConditionalRequiredArg<T, P>) {}
    // ...
    

    但是,如果您想进行更多更改,请查看以下内容:

    /*
     * You could remove the conditional type to get a better inference on the generics
     * that are used and simply check the typeof _arg1 and if it is string as you had
     * defined in the ConfitionalRequiredArg it will use a type in the generic arg
     * you would then have to provide
     */
    function func<P>(_arg1: string | number, _arg2?: typeof _arg1 extends string ? P | undefined : P) {}
    
    func<string>('foo', 4); // ts error 4 is not assignable to type string | undefined
    

    最后,要使参数成为可选参数,请使用? 运算符。

    Playground

    【讨论】:

      【解决方案4】:

      正如@daylily 所说,如果您能够使用签名重载语法,那么这绝对是要走的路。但是,如果您需要推断泛型,那么我通常会有条件地生成一个元组:

      function assertPerson<
          Age extends number
      >(
          ...args: 0 extends Age ? [age: Age] : [age: Age, name: string]
      ) {
          const [age, maybeName] = args; // [number, string | undefined]
      }
      
      assertPerson(2, "hey");
      assertPerson(0)
      

      TypeScript Playground Link

      【讨论】:

      • 有趣的解决方案,谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      • 2022-12-01
      • 2021-09-17
      相关资源
      最近更新 更多