首页 > 解决方案 > 为什么使用条件运算符会导致交集类型?

问题描述

我正在尝试创建一个通用函数,该函数根据其参数的类型有条件地返回值,但我一直在尝试实现返回类型。

假设有一个类型Basket

type Basket = {
    Fruit: 'banana',
    Veggie: 'tomato'
}

现在,如果我想根据传递给函数的参数有条件地返回“香蕉”或“番茄”,我无法让它编译:

const f1 = <T extends keyof Basket>(t: T): T extends 'Fruit'? 'banana': 'tomato' => {
    if (t == 'Fruit') {
        return 'banana' //Error on this line - doesn't compile -- Type '"banana"' is not assignable to type '"banana" & "tomato"
    } else {
        return  'tomato' //Error on this line - doesn't compile -- Type '"tomato"' is not assignable to type '"banana" & "tomato"
    }
}

现在,当我在传递正确的泛型参数后实例化它时,我得到了我期望的类型,但它没有编译

const doesntCompile: 'banana' = f1<'Fruit'>('') //type: 'banana', which is what I want ... but this doesn't compile due to the error above.

但是,如果我不使用泛型,我会得到一个 sum 类型

//This compiles
const f2 = <T extends keyof Basket>(t: string): Basket[keyof Basket] => { //return type is 'banana' | 'tomato'
    if (t == 'yellow') {
        return  'banana'
    } else {
        return  'tomato'
    }
}
const complies: 'banana' | 'tomato' = f2<'Fruit'>('') //type: 'banana' | 'tomato', but I want the type here to be 'banana'

现在它编译得很好,但我失去了类型安全的好处。

在保留泛型的同时如何让这个示例工作?任何帮助都深表感谢。

标签: typescript

解决方案


关于您的问题,它来自延迟的条件类型。查看打字稿文档:https ://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types 。(条件类型的搜索被推迟到页面中的正确位置)。

最简单的解决方案是使用更宽松的单独实现签名,同时将公共签名保留为对调用者更好的条件类型:

type Basket = {
    Fruit: 'banana',
    Veggie: 'tomato'
}

function f3 <T extends keyof Basket>(t: T): Basket[T]; 
function f3 <T extends keyof Basket>(t: string): Basket[keyof Basket] {
    if (t == 'Fruit') {
        return  'banana'
    } else {
        return  'tomato'
    }
}

const complies2 = f3('Fruit'); // complies2 is "banana"

注意:箭头函数不适用于函数重载。


推荐阅读