【问题标题】:Typescript autocompletion for conditionally returned function based on parameter of first function基于第一个函数参数的有条件返回函数的打字稿自动完成
【发布时间】:2023-01-24 19:06:49
【问题描述】:

我已经为此苦思冥想了一段时间,所以我决定在 Stackoverflow 上提出这个问题,希望有人能够帮助我。这是我的问题的简化代码 sn-p 版本:TypeScript Playground

解释:

一旦使用某个option 参数执行,我希望在example 函数上自动完成。

所以如果我输入example("foo").<autocompletion expects fooFunctions interface>。所以它会告诉我 example("foo").fooFunction() 是唯一的选择,因为第一个函数的参数是“foo”。

如果我输入example("bar").<autocompletion expects barFunctions interface>。所以它会告诉我 example("bar").barFunction() 是唯一的选择,因为第一个函数的参数是“bar”。

然而现在的问题是两个返回对象都期望另一个函数在那里,即使我不希望那样......

有没有 Typescript 专家可以帮助我?

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    您可以使用重载来实现您的目标:

    function example(options: 'foo'): fooFunctions;
    function example(options: 'bar'): barFunctions;
    function example(options: 'foo' | 'bar') : fooFunctions | barFunctions {
       // The code
    }
    
    example('foo').fooFunction(); // Autocompletion works as expected
    example('bar').barFunction(); // Autocompletion works as expected
    exmaple('other'); // Fails because it is not an accepted
    

    或者,您可以使用 keyof 来维护类似于您的语法:

    interface returnFunctions {
      bar: barFunctions,
      foo: fooFunctions
    }
    
    
    const example = <T extends keyof returnFunctions>(options: T): returnFunctions[T] => {
       // The code
    }
    

    这也使自动补全功能如您所愿地工作。

    【讨论】:

      【解决方案2】:

      您需要实际使用类型参数作为options 的类型:

      const example = <T extends options>(options: T): returnFunctions[T] => {
         ///...
      }
      
      
      example("bar").barFunction()
      example("foo").fooFunction()
      

      Playground Link

      现在使用这个版本,你在实现中仍然有错误,因为 TypeScript 不能真正遵循如果你缩小 option 返回的类型也会缩小。

      您可以使用类型断言解决此问题:

      
      const example = <T extends options>(options: T): returnFunctions[T] => {
        if (options === "bar") {
          return {
            barFunction() {
              console.log("It's the bar function");
            }
          } as returnFunctions[T]
        }
      
        if (options === "foo") {
          return {
            fooFunction() {
              console.log("It's the foo function");
            }
          } as returnFunctions[T]
        }
      
        throw new Error(`Expected either foo or bar but got ${options}`)
      }
      

      Playground Link

      或者您可以改用重载,公共签名是通用的,而实现签名不是通用的。虽然这不会增加安全性(您有责任确保参数和返回类型一致,但它确实使代码看起来更好 IMO)

      function example<T extends Options>(options: T): ReturnFunctions[T]
      function example(options: Options): ReturnFunctions[Options] {
        if (options === "bar") {
          return {
            barFunction() {
              console.log("It's the bar function");
            }
          }
        }
      
        if (options === "foo") {
          return {
            fooFunction() {
              console.log("It's the foo function");
            }
          }
        }
      
        throw new Error(`Expected either foo or bar but got ${options}`)
      }
      

      Playground Link

      此外,我将从 ReturnFunctions 接口派生选项,并使用大写字母作为类型(但那些只是吹毛求疵)Playground Link

      【讨论】:

        【解决方案3】:

        你可以在这里使用策略模式:

        type options = "bar" | "foo";
        
        interface barFunctions {
          barFunction: () => void;
        }
        
        interface fooFunctions {
          fooFunction: () => void;
        }
        
        interface returnFunctions {
          bar: barFunctions,
          foo: fooFunctions
        }
        
        const fnStrategy: returnFunctions = {
          bar: {
            barFunction() {
              console.log("It's the bar function");
            }
          },
          foo: {
            fooFunction() {
              console.log("It's the bar function");
            }
          }
        }
        
        const example = <T extends options>(options: T): returnFunctions[T] => fnStrategy[options]
        
        const result = example('foo') // fooFUnctions
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-09-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多