当前位置: 首页 > 知识库问答 >
问题:

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

史鹏云
2023-03-14

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

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");

但是,如果使用union type“a”|“b”的值调用foo函数,则会出现类型错误:

// 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);
}

问:既然TypeScript对如何调用foo没有任何影响,为什么它会强迫我缩小选项的范围?

我总是叫foo

把我的问题打印出来


共有1个答案

越英韶
2023-03-14
function foo(options: "a"): "a";
function foo(options: "b"): "b";
function foo(options: "a" | "b"): "a" | "b" {

最后一行是函数实现的开始,但它不是外部世界可见的类型的一部分。因此,对于您编写的代码,实际上不允许传入类型为“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" {

 类似资料:
  • 我习惯像这样声明数组内联: 为什么我不能对函数执行相同的操作?假设我有一个类,其中包含and 方法,这是有效的: 但是,这不是: 它不喜欢内联数组声明,编译器错误是“不能创建函数的泛型数组” 编辑 我认为我的问题不是建议的副本,因为我想使用数组初始值设定项语法静态定义一组函数

  • 我正在开发一个简单的 C 程序,并且很难理解我遇到的编译器错误。该问题是由于我尝试从基类创建派生类引起的。我在下面发布了具有相同结构的代码,但更改了名称。 BaseClass.h DerivedClass.h 派生类.cpp 在尝试编译此代码时,所有虚拟方法都会出现以下错误: 一旦我在“衍生类”中声明了这些方法,错误就会消失,因为编译器现在知道这些方法了。 然而,我很困惑。为什么有必要重新声明派生

  • 问题内容: 我很好奇为什么必须这样声明float文字: 代替 为什么默认类型是双精度类型,为什么编译器不能通过查看赋值的左侧来推断它是浮点型的?Google仅提供关于默认值的解释,而不是为什么如此。 问题答案: 为什么默认类型是双精度型? Java语言的设计者最好问这个问题。他们是唯一知道做出语言设计决定的 真正 原因的人。但我希望推理遵循以下几条原则: 他们需要区分两种类型的文字,因为从数学的角

  • 问题内容: 目前,我正在研究Sams出版的《 24小时自学Android应用程序开发》一书。我是Java,Android或其他方面的新手。我在ActionScript 3中具有非常扎实的背景,该语言与Java具有足够的相似性,因此该语言本身并不难掌握,但对于本书中某些代码示例的基本原理,我仍然存在一些疑问。例如,以下是第9小时的示例代码随附的函数: 在此函数签名中,作者已将scoreTable参数

  • 问题内容: 考虑以下代码: 如果我们在超类中有一个构造函数,那么我们为子类构造的每个对象(例如,用于类调用的对象及其父对象)都将调用它。 为什么会这样? 该程序的输出为: 在超类的构造函数中 在子类的构造函数中 总和是25 在超类的构造函数中 在子类的构造函数中 总和是29 问题答案: 因为它将确保在调用构造函数时,它可以依赖于其超类中已初始化的所有字段。 请参阅此处的 3.4.4

  • 这是对我上一个问题的延续,并同意这个问题的答案 包装类声明 Java将原始数据类型包装到包装类中,那是为什么呢 不允许,但 是允许的。