【问题标题】:Typescript call signature inference打字稿调用签名推断
【发布时间】:2017-11-30 18:10:13
【问题描述】:

我正在尝试将以下 Flow sn-p 转换为 Typescript:

type Handler<Data> = (data: Data) => void
type Foo = { foo: string }
type AnyRequest = (path: '/foo', handler: Handler<Foo>) => void
type FooRequest = (path: string, handler: Handler<any>) => void

type RouterRequest = AnyRequest | FooRequest


function router(request: RouterRequest) {
   request('/foo', (data) => {
      // here data should be of type Foo
   })

   request('/bar', (data) => {
      // here data should be of type any  
   })  
}

这里的流可以通过使用path参数正确推断data的类型。见running snippet

Typescript 中的相同代码无法推断data 的类型 将此代码粘贴到playground 给我这个错误

无法调用类型缺少调用签名的表达式。类型“RouterRequest”没有兼容的调用签名。

有什么方法可以在 Typescript 中实现类似的功能吗?

【问题讨论】:

  • 请详细说明The same code in Typescript fail
  • 我的意思是 Typescript 无法推断数据的类型。 Playground 中的实际错误是:“无法调用类型缺少调用签名的表达式。类型 'RouterRequest' 没有兼容的调用签名。”
  • 嗯。不知道它应该如何工作。 request 的类型在我看来是无法推断出来的,因为预先不知道是 AnyRequest 还是 FooRequest 被传入。我希望我能更好地理解 TS 类型推断。
  • 换句话说,我认为,在 TypeScript 中,您需要明确检查所提供参数的类型并在其上进行分支
  • 是的,或者按照@jcalz 的建议去做!

标签: typescript flowtype


【解决方案1】:

这是一个RouterRequest 类型,它允许完全上下文输入...

type RouterRequest = {
  (path: "/foo", handler: Handler<Foo>): void;
  (path: string, handler: Handler<any>): void;
}

完整示例:

type Handler<Data> = (data: Data) => void;
type Foo = { foo: string }

type RouterRequest = {
  (path: "/foo", handler: Handler<Foo>): void;
  (path: string, handler: Handler<any>): void;
}

function router(request: RouterRequest) {
    request('/foo', (data) => {
        // data is of type Foo
    })

    request('/bar', (data) => {
        // data is of type any  
    })  
}

【讨论】:

  • 谁否决了这个正确答案?我是来写这篇文章的,Fenton 秒杀我
  • 非常感谢,这正是我想要的!
【解决方案2】:

认为你的意思是RouterRequestAnyRequestFooRequest交集,而不是它们的联合。像这样:

type RouterRequest = AnyRequest & FooRequest;

AnyRequest | FooRequest 类型是指您不知道它是 AnyRequest 还是 FooRequest 的东西。 TypeScript 或多或少地警告你它不知道它是哪一个,所以它根本不会让你调用它(尽管它可能should 让你用参数的交集来调用它,但我离题了。 )

但您希望能够使用任一组参数调用它。这更像是overloaded function(或函数类型的交集)而不是联合。

如果您更改上述行,它应该对您有用,假设 RouterRequest 真的可以以两种方式调用。

希望有所帮助;祝你好运!

【讨论】:

  • 不错的答案@jcalz
  • 是的,这也有效,谢谢! &amp; 与输入 type RouterRequest = { (path: "/foo", handler: Handler): void; 有何不同? (路径:字符串,处理程序:处理程序):无效; }
  • 本质上是一样的......两个函数类型的交集表现为重载(这意味着交集不是严格可交换的:A &amp; B 的行为可能与 B &amp; A 不同)。
【解决方案3】:

这将起作用:

type RouterRequest = {
    (path: '/foo', handler: Handler<Foo>) :void  
    (path: string, handler: Handler<any>):void;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 2021-06-08
    相关资源
    最近更新 更多