【问题标题】:Typescript overloading type boolean is not assignable to type falseTypescript 重载类型 boolean 不能分配给 false 类型
【发布时间】:2018-06-19 16:02:25
【问题描述】:

我有一个根据选项键值返回不同类型的方法。

class Test {
  getData(options: { obj: true }): Object;
  getData(options: { obj: false }): any[];
  getData(): any[];
  getData(options = { obj: false }): Object | any[] {
    if (options.obj) {
      return {};
    } else {
      return [];
    }
  }
}

当将obj 作为true 传递时,我将返回对象,否则返回数组。效果很好。

const instance = new Test();
const result = instance.getData({ obj: true }); // inffered as array
const result2 = instance.getData(); // inffered as object

问题是当我需要使用动态值时它会抛出一个错误:

boolean 类型不能分配给 false 类型

function getResult(obj: boolean = false ) {
  return instance.getData({ obj });
}

有什么问题?

【问题讨论】:

    标签: javascript typescript


    【解决方案1】:

    由于{ obj } 的类型在编译时仅称为{ obj: boolean },编译器无法知道选择任何重载,因此您必须显式提供采用{ obj: boolean } 的重载(因为实现签名不算作函数的公共签名),在这种情况下编译器不会做任何魔术:

    class Test {
        getData(options: { obj: true }): Object;
        getData(options: { obj: false }): any[];
        getData(options: { obj: boolean }): Object | any[];
        getData(): any[];
        // This signature is the implementation and is not conidered when resolving the method 
        getData(options = { obj: false }): Object | any[] {
            if (options.obj) {
                return {};
            } else {
                return [];
            }
        }
    } 
    

    编辑

    您还可以在方法签名中使用条件类型,这样可以减少签名的数量:

    class Test {
        getData<T extends boolean>(options: { obj: T }): T extends true ? Object : any[];
        getData(): any[];
        // This signature is the implementation and is not conidered when resolving the method 
        getData(options = { obj: false }): Object | any[] {
            if (options.obj) {
                return {};
            } else {
                return [];
            }
        }
    }
    
    
    const instance = new Test();
    const result = instance.getData({ obj: true }); // inffered as array
    const result2 = instance.getData(); // inffered as object
    
    function getResult(obj: boolean = false) {
        return instance.getData({ obj }); // inferred as Object|any[]
    }
    

    由于type boolean = true | false 和条件类型分布在联合上, 当Tboolean 时,T extends true ? Object : any[]; 将为Object|any[]。当Ttrue 时,返回为Object,当Tfalse 时,返回为any 都符合预期

    【讨论】:

    • 所以我不能让 typescript 推断出动态函数的返回类型?
    • 使用我添加的额外签名 getResult 会正确推断返回类型,但您需要在 getData 上添加额外签名。由于类型为Boolean 的问题没有任何签名匹配,并且编译器无法选择两个签名。可能有条件类型的方法,让我检查一下..
    • @undefined 还添加了一个条件类型方法,对我来说看起来更好,但你自己判断吧:)
    【解决方案2】:

    例如,您不能像在 C# 中那样重载 TypeScript 中的方法。您需要组合类型,如下所示:

    class Test {
    
      getData(options: {obj: boolean} = { obj: false }): Object | any[]  {
       if (options.obj) {
            return {};
          } else {
            return [];
          }
       }
    }
    

    当你多次重新声明同名函数时,你只会得到最后一个作为最终定义,在运行时。

    【讨论】:

    • 你可以重载方法签名!你不能有多个实现
    • 不,确实没有。它允许在没有实现的情况下声明方法,但它不将其用作类型结构,使其只是语法糖。您必须在实际实现主体的函数中声明类型
    • 是的,问题具体是如何使用多个签名的语法糖。您的答案没有实现相同的类型检查功能,您只是删除了签名,它们在那里是有原因的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-24
    • 2017-06-29
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    • 2019-01-04
    • 2023-01-22
    相关资源
    最近更新 更多