为什么重载函数声明有时会强制无用的类型缩小?

2023-12-06

给出重载函数语句的以下实现:

function foo(options: "a"): "a";
function foo(options: "b"): "b";
function foo(options: "a" | "b"): "a" | "b" {
    switch (options) {
        case "a":
            return `a`;
        case "b":
        default:
            return `b`;
    }
}

我可以这样调用该函数:

// this works
const url1 = foo("a");
const url2 = foo("b");

但是,如果我调用foo使用联合类型的值调用时的函数"a" | "b":

// function call (inside of wrapped function)
type Options = "a" | "b";
const wrapper = (options: Options) => {
    // function overloading forces the caller to narrow the type
    const url = foo(options); // Error: Type '"a"' is not assignable to type '"b"'.
}

我可以通过解决这个问题

function foo(options: "a"): "a";
function foo(options: "b"): "b";
function foo(options: "a" | "b"): "a" | "b" {
    switch (options) {
        case "a":
            return "a";
        case "b":
        default:
            return "b";
    }
}

type Options = "a" | "b";
const wrapper = (options: Options) => {
    // Solution: Calling function 'foo' in the exact same way
    const url = options === "a" ? foo(options) : foo(options);
}

Question:为什么 TypeScript 强迫我缩小范围options值,因为它对我的调用方式没有影响foo?

我总是打电话foo as foo(options)。如果重载的类型签名差异较大,例如,如果某些重载包含可选参数值,TS 当然应该提示我缩小类型。但难道不应该推断在这样的场景中没有必要吗?

我的问题的 TypeScript Playground


function foo(options: "a"): "a";
function foo(options: "b"): "b";
function foo(options: "a" | "b"): "a" | "b" {

最后一行是函数实现的开始,但它不是外部世界可见的类型的一部分。所以用你写的代码,传递一些类型"a" | "b"实际上是不允许的。只是"a" or "b"他们自己。

错误消息可能包含以下文本,它试图指出问题,但如果您以前从未见过它,可能很难理解它的含义:

针对此实现的调用将成功,但重载的实现签名在外部不可见。

解决方法是在定义中再添加一个重载:

function foo(options: "a"): "a";
function foo(options: "b"): "b";
function foo(options: "a" | "b"): "a" | "b";
function foo(options: "a" | "b"): "a" | "b" {
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么重载函数声明有时会强制无用的类型缩小? 的相关文章

随机推荐