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

And*_*dru 3 typescript

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

\n
function foo(options: "a"): "a";\nfunction foo(options: "b"): "b";\nfunction foo(options: "a" | "b"): "a" | "b" {\n    switch (options) {\n        case "a":\n            return `a`;\n        case "b":\n        default:\n            return `b`;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我可以这样调用该函数:

\n
// this works\nconst url1 = foo("a");\nconst url2 = foo("b");\n
Run Code Online (Sandbox Code Playgroud)\n

foo但是,如果在使用联合类型的值调用该函数时调用该函数,则会出现类型错误"a" | "b"

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

我可以通过解决这个问题

\n
function foo(options: "a"): "a";\nfunction foo(options: "b"): "b";\nfunction foo(options: "a" | "b"): "a" | "b" {\n    switch (options) {\n        case "a":\n            return "a";\n        case "b":\n        default:\n            return "b";\n    }\n}\n\ntype Options = "a" | "b";\nconst wrapper = (options: Options) => {\n    // Solution: Calling function \'foo\' in the exact same way\n    const url = options === "a" ? foo(options) : foo(options);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

问题:为什么 TypeScript 强制我缩小options值,因为它对我的调用方式没有影响foo

\n

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

\n

我的问题的 TypeScript Playground

\n

Nic*_*wer 9

function foo(options: "a"): "a";
function foo(options: "b"): "b";
function foo(options: "a" | "b"): "a" | "b" {
Run Code Online (Sandbox Code Playgroud)

最后一行是函数实现的开始,但它不是外部世界可见的类型的一部分。因此,对于您编写的代码,"a" | "b"实际上不允许传递某种类型。只是"a"或者"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" {
Run Code Online (Sandbox Code Playgroud)