【问题标题】:Overloads cannot differ only by return type重载不能仅因返回类型而异
【发布时间】:2014-09-21 05:44:56
【问题描述】:

我正在尝试重载一个函数,因此当在其他地方使用该函数时,它会正确显示结果,即项目数组、void 或单个项目:

getSelected(type): void;
getSelected(type): IDataItem;
getSelected(type): IDataItem[];
getSelected(type:string, one:boolean = true):any {
   if (!type) {
       return;
   }
   if (one) {
      return _.reduce<IDataItem, IDataItem>(sections[type], (current: IDataItem, p: IDataItem) => {
         return p.selected === true ? p : current;
      }, void 0);
   }

   return _.filter<IDataItem>(sections[type], (p: IDataItem):boolean => {
     return p.selected === true && p.enabled === true;
   });
}

它给了我错误 “错误 TS2175:重载不能仅因返回类型而异。”。那么,我如何才能表明返回类型的多种可能性呢?

【问题讨论】:

    标签: typescript overloading


    【解决方案1】:

    关于您的原始代码有几点值得注意...

    你不能调用实现签名。

    这些是“重载签名” - 您可以调用它们。

    getSelected(type): void;
    getSelected(type): IDataItem;
    getSelected(type): IDataItem[];
    

    下一行是“实现签名”——你不能直接调用它。

    getSelected(type:string, one:boolean = true):any {
    

    这意味着就目前而言,您永远无法传递 one 参数。

    您需要输入type 参数。

    您的重载没有为 type 参数指定类型,它们将具有 any 类型 - 但我认为您可能希望将其限制为字符串。每个签名都需要注解...

    type: string
    

    根据布尔参数值不同

    您的签名表明如果您在one 参数中传递true,您将得到一个结果。如果你传错了,你会得到多个结果。我们现在可以使用它了,因为 TypeScript 已经变得更棒了。见下文...

    工作重载。

    鉴于所有这些信息,您可以使用:

    getSelected(type: string): void;
    getSelected(type: string, one: true): IDataItem;
    getSelected(type: string, one: false): IDataItem[];
    getSelected(type: string, one: boolean = true): any {
        // ... code!
    }
    

    当您调用它时,将根据传递的参数推断类型。这是它的形状,您的代码已从实际方法中删除...

    interface IDataItem {
        name: string;
    }
    
    class Example {
        getSelected(type: string): void;
        getSelected(type: string, one: true): IDataItem;
        getSelected(type: string, one: false): IDataItem[];
        getSelected(type: string, one: boolean = true): void | IDataItem | IDataItem[] {
            // ... code!
        }
    }
    
    const example = new Example();
    
    // void return
    example.getSelected('just type');
    
    // IDataItem
    const a = example.getSelected('x', true);
    
    // IDataItem[]
    const b = example.getSelected('x', false);
    

    【讨论】:

    • 这个答案可能已经过时了。详情请关注this
    【解决方案2】:

    使用泛型来帮助编译器确定正确的值:

    getSelected<T>(type:string, one:boolean = true): T {
        // ...
    }
    
    getSelected<void>('abc');
    var aDataItem = getSelected<IDataItem>('abc');
    var aList = getSelected<IDataItem[]>('abc');
    

    See also the documentation.

    【讨论】:

    • 看来我不能对班级成员使用泛型......有什么解决方法吗?它给了我 TS2011:类型“IDataItem”不可分配给类型“T”
    • 不错的建议-尽管如您的代码示例所示,有一个小问题。您在两次调用中都使用'abc' 调用该方法,但期望得到不同的返回类型,这是极不可能的。当然,您可以更新示例代码 - 但这种行为仍然存在。
    • 好的,Steve 和 Ryan 建议的解决方案更好。如果您在编译时就知道返回类型,那么您应该避免在运行时再次测试该类型。
    • 就个人而言,我更喜欢 Tarh 的清晰度,而不是拉丁语的 Paleo,但如何称呼自己是您的选择。 :) 至于技术部分,你会说the other answer based on generics 过于挑剔和限制吗?
    • @KonradViltersten function getI18n&lt;A extends string[] | string&gt;(id: A): A 没问题。我个人会在适当的时候在我的代码中使用相同的技巧。
    【解决方案3】:

    如果您可能根据传入的数据的内容返回任何内容,并且这些可能的返回值之间没有共同的类型,则应将返回类型声明为 any 并强制调用使用类型断言的代码。

    我不喜欢 Paleo 的建议,因为它暗示了没有类型安全的地方。

    从单个函数调用返回不同类型的数据是一种代码异味;它使调用者有很多责任来了解输入和输出之间的关系。最好有getSelectedSinglegetSelectedMultiplegetSelectedNone 之类的东西。

    【讨论】:

    • 我明白了,我真的“习惯”了松散的 Javascript,在使用 Typescript 时我需要改变我的心态(这是我做出改变的主要原因)
    • 这个答案可能已经过时了。详情请关注this
    • 另外,什么是tarh?我在页面上查看了该用户的帖子,但没有找到。
    • @KonradViltersten 这是我在这里的第一个伪。所以我编辑了这个答案来改变我自己的名字。 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-30
    • 1970-01-01
    • 2019-05-11
    • 1970-01-01
    相关资源
    最近更新 更多