代码之家  ›  专栏  ›  技术社区  ›  Justin Grant

参数为条件元组类型时重载参数的智能感知命名

  •  0
  • Justin Grant  · 技术社区  · 6 年前

    在TypeScript3.1中,我有一个泛型函数,其参数为 (TInput, string) (string) 取决于泛型的类型参数 TInput extends undefined . 目前我正在使用新的 generic rest parameters 将函数参数键入为条件元组类型的功能:

    function test (
        ...args: TInput extends undefined ? [string] : [TInput, string]): void
    )
    

    这几乎是完美的工作。当我用具体类型实例化泛型函数时,VSCode只显示应用于该泛型类型的重载。耶!

    args_0 args_1 input 对于泛型参数(如果存在的话)和 name 对于字符串参数。

    是否有任何方法可以在不丢失参数计数和类型的(正确的)Intellisense的情况下为这些参数附加更友好的名称?

    顺便说一句,只要核心需求工作正常,我可以使用不使用元组的解决方案,也就是说:当泛型函数用实数类型实例化并且我将鼠标悬停在VSCode中的函数上时,我会看到对该具体类型有效的正确参数计数、名称和类型。

    我试着添加重载(见下面的注释代码),但不知道如何编译重载。我得到:

    在这个示例的早期迭代中,我可以使用类型转换来获取要编译的重载,但这反过来又破坏了参数计数和类型的Intellisense,其中“break”表示(与下面的代码不同)两个重载始终以Intellisense显示,即使泛型类型参数应该将列表缩小为一个有效的超载。

    const makeTest = <TInput>() => {
    //  Adding the overloads below doesn't work as expected. There are two problems: 
    //    1. compiler error: "Overload signature is not compatible with function implementation. ts(2394)"
    //    2. if I use a cast to get around the compile error, both overloads show in Intellisense regardless of TInput
    //  function test (name: string): void; 
    //  function test (input: TInput, name: string): void;
        function test (...args: TInput extends undefined ? [string] : [TInput, string]): void {
            // do stuff
        }
        return test;
    }
    
    // type inferred as: const f1: (args_0: string) => void
    const f1 = makeTest<undefined>(); 
    
    // type inferred as: const f2: (args_0: number, args_1: string) => void
    const f2 = makeTest<number>();
    

    这是一个 playground link

    顺便说一句,我知道我可以通过颠倒参数顺序来简化这个过程,但是改变它面向JS的签名是不实际的。我现在只能更改TS的输入。另外,即使参数是反向的,我也非常喜欢用特定类型实例化泛型将如何移除无效的重载,我不知道这是否适用于传统的可选参数。

    1 回复  |  直到 6 年前
        1
  •  1
  •   Titian Cernicova-Dragomir    6 年前

    我只需将函数类型断言为依赖于 TInput ,这会给你更好的智能感。您不能在rest参数中轻松指定元组的参数名:

    const makeTest = <TInput>() => {
    
        function test (...args: [string] | [TInput, string]): void {
            // do stuff
        }
        return test as (TInput extends undefined ? ((name:string) => void) : ((input: TInput, name: string) => void);
    }
    

    或具有实现和公共签名的版本 makeTest

    function makeTest<TInput>(): (TInput extends undefined ? ((name: string) => void) : ((input: TInput, name: string) => void))
    function makeTest<TInput>(): ((name: string) => void) | ((input: TInput, name: string) => void) {
    
        function test(...args: [string] | [TInput, string]): void {
            // do stuff
        }
        return test;
    }