打字稿条件类型:推断有效,但编译器拒绝实现

时间:2018-10-30 19:49:33

标签: typescript conditional-types

我已经成功地使用了Typescript的条件类型,但是我经常发现,尽管我可以表达类型签名,但是在函数的实现中,即使我知道实现是正确的,也必须使用any

示例,此定义:

type ExportType<InputType extends string|undefined> =
    string extends InputType ? undefined : ()=>void;

function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType>;

(我知道我可以使用重载,但是我的实际问题更加复杂,对于实际问题,重载并不现实)

实际上,签名是说“如果参数为string,我将返回()=>void,如果参数为undefined,我将返回undefined

这很好用。玩convert("x")convert(undefined)表示打字稿与此定义一致。

但是实际上尝试实现此功能时:

type ExportType<InputType extends string|undefined> =
    string extends InputType ? undefined : ()=>void;

function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType> {
    if (input) {
        return ()=>{console.log("OK");};
    } else {
        return undefined;
    }
}

这不能编译。打字稿说:

error TS2322: Type '() => void' is not assignable to type 'ExportType<InputType>'.

         return ()=>{console.log("OK");};
         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

但是该行在if (input)中,因此在这一点上我们知道输入不是undefined,因此它必须是string,因此我们必须返回{{1} } ...但是看来编译器不够聪明,无法看到它。

将该行更改为:

() => void

使它工作,但令人失望...

那么有没有办法为打字稿让我们表达的签名编写完全类型安全且经过检查的实现?

1 个答案:

答案 0 :(得分:1)

Typescript不允许您将值分配给未解析的条件类型(即仍包含自由类型参数的条件类型)。您可以使用发现的演员表,也可以使用单独的实现签名:

type ExportType<InputType extends string|undefined> =
    string extends InputType ? undefined : ()=>void;

function convert<InputType extends string|undefined>(input: InputType): ExportType<InputType> 
function convert(input: string|undefined): undefined | (()=>void) {
    if (input) {
        return ()=>{console.log("OK");};
    } else {
        return undefined;
    }
}