代码之家  ›  专栏  ›  技术社区  ›  Automatico

重复/交替函数参数

  •  1
  • Automatico  · 技术社区  · 5 年前

    例如,如果我希望参数在字符串和数字之间交替

    function someFunction(a: string, b: number){
      // 1 repetition
    }
    function someFunction(a: string, b: number, a2: string, b2: number){
      // 2 repetition
    }
    function someFunction(a: string, b: number, a2: string, b2: number, a3: string, b3: number){
      // 3 repetition
    }
    // and so on
    

    当然,通过spread运算符可以实现类似的功能,但据我所知,我无法替换数据类型。

    function someFunction(...someInput: (string|number)[]){
      // all input is now string|number, not string, then number, then string, and so on.
    }
    
    0 回复  |  直到 5 年前
        1
  •  4
  •   jcalz    5 年前

    对此有不同的方法。这是一种工作和不工作的方式。可能还有其他方式继续,但我现在时间紧迫:

    type SameLength<T> = { [K in keyof T]: any };
    type Cyclic<T extends readonly any[], C extends readonly any[]> = readonly [] |
      (T extends [...SameLength<C>, ...infer U] ? readonly [...U, ...C] : readonly [...C]);
    
    function someFunction<T extends readonly (string | number)[]>(
      ...args: T & Cyclic<T, [string, number]>
    ) { ... }
    

    这应该主要从打电话的人的角度来进行。这个想法是 args Cyclic<[A, B, C, D], [string, number] [C, D, string, number] . 如果 [A, B, C, D] 都是一样的,这意味着它必须是一样的 [string, number, string, number]

    实际上,函数允许和不允许按您想要的方式调用。

    someFunction(); // okay
    someFunction("a"); // error
    someFunction("a", 1); // okay
    someFunction("a", "b"); // error
    someFunction("a", 1, "b", 2); // okay
    someFunction("a", 1, "b", 2, "c", 3); // okay
    

    不幸的是,这些错误并不是特别有用,特别是因为它们都出现在第一个参数上(这是一个bug, microsoft/TypeScript#28505 ),他们抱怨被分配给 never . 这


    内部 实施 在功能方面,情况更糟。编译器不知道什么类型 T 将是,它不能一般地推断其他元素都是 string number . 你所得到的只是:

    function someFunction<T extends readonly (string | number)[]>(
      ...args: T & Cyclic<T, [string, number]>
    ) {
      const a = args[0] // string
      const b = args[1] // number
      const c = args[2] // string | number 😢
    }
    

    因此,在函数内部,您需要使用 assertion args[2*k] 是一个 string | undefined args[2*k+1] 是一个 number | undefined


    所以这还不够完善,我建议在生产代码中使用它。

    Playground link to code


    type StringNumberAlternating<L extends number,
      A extends readonly any[] = readonly []> = (string | number)[] & (
        undefined extends [...A][L] ? A['length'] extends L ? A :
        StringNumberAlternating<L, [string, number, ...A]> : A)
    
    function someFunction<T extends StringNumberAlternating<T['length']>>(
      ...args: T
    ) { }
    

    Playground link to code


    type SN<T extends readonly any[] = readonly []> = readonly [] | readonly [string, number, ...T]
    type SNT<L extends number, A extends readonly any[] = readonly []> =
      A | (A['length'] extends L ? never : SNT<L, readonly [string, number, ...A]>);
    type StringNumberTuples = SNT<20>; // max length of 20
    
    function someFunction(...args: StringNumberTuples) {
      const a = args[0] // string | undefined
      const b = args[1] // number | undefined
      const c = args[2] // string | undefined
      const d = args[Math.floor(Math.random() * 100)] // string | number 🤷‍♂️
    }
    

    这有很好的错误消息(除了由于microsoft/TypeScript#28505的原因,它们始终在第一个参数上),并且函数签名不再是通用的,因此更简单。主要的限制是你必须选择一些最大长度来支撑;这有点像使用重载,除了你可以只传递一个数字,比如20,而不是写10个重载签名。

    Playground link to code

    推荐文章