TypeScript:如何使用条件返回类型实现可调用类型?

时间:2019-01-27 06:18:46

标签: typescript typescript-typings

当接口Foo具有条件类型作为返回类型时,如何实现?

interface Foo {
    <A, B>(a: A, b: B): A extends B ? string : number
}

const foo: Foo = (a, b) => a === b ? 'str' : 123

编译器会产生此错误:

Type '"str" | 123' is not assignable to type 'A extends B ? string : number'. Type '"str"' is not assignable to type 'A extends B ? string : number'.

Playground

我已经看到this个问题,但看不到如何将其转换为示例。另外,与解决方法相比,我想知道什么是正式/正确的方法。

UPD:我像提到的问题一样解决了问题,但是Unional的回答确实帮助我理解了问题。我是这样解决的:

interface Foo {
    <A, B>(a: A, b: B): A extends B ? string : number
    <A, B>(a: A, b: B): string | number
}

1 个答案:

答案 0 :(得分:1)

您的类型定义很好。

问题在于您似乎过于依赖类型系统来指导开发。

由于您将类型定义和实现分开,因此编译器自然会以不同的方式看待它们。

在这种情况下,请随时将实现强制转换为any

您看到的错误是由于类型推断而为您的实现创建了类型(a: any, b: any) => "str" | 123

因此编译器抱怨该类型不能满足您在Foo中定义的类型。

没有其他信息,这是编译器可以做的最好的事情。

当然,在实现代码时,编译器推断的类型最终可能会满足您定义的类型。

但是请记住,使用TypeScript的主要目的是提供信息以使用您编写的代码。使用类型来辅助实现是很好的做法,但应该将其视为奖励。

编译器并不完美,您是唯一真正了解您意图的编译器。

这就是为什么有时需要使用any来进行操作的原因,请使用它(当然要始终保持谨慎)。

这表明您的类型有效:

interface B { x: string }

interface A extends B { }

let a: A
let b: B
let c: string
const y = foo(a, b)  // y is string
const x = foo(c, b)  // x is number

请记住编写单元测试以证明您的实现。 类型可以帮助您避免一类错误,但不是所有错误。

更新:从TypeScript 3.2开始,我认为控制流分析(类型推断)不能推断条件类型。