【问题标题】:'any' vs 'Object'“任何”与“对象”
【发布时间】:2013-09-28 11:09:03
【问题描述】:

我正在查看 TypeScript 代码并注意到它们使用:

interface Blablabla {

   field: Object;

}

使用Objectany 有什么好处,如:

interface Blablabla {

  field: any;

}

【问题讨论】:

    标签: typescript


    【解决方案1】:

    Object 似乎是比任何声明都更具体的声明。来自 TypeScript 规范(第 3 节):

    TypeScript 中的所有类型都是单一顶级类型的子类型,称为 任意种类。 any 关键字引用此类型。 Any 类型是 一种可以无约束地表示任何 JavaScript 值的类型。 所有其他类型都归类为原始类型、对象类型或 类型参数。这些类型引入了各种静态约束 他们的价值观。

    还有:

    Any 类型用于表示任何 JavaScript 值。的一个值 任何类型都支持与 JavaScript 中的值相同的操作,并且 对 Any 上的操作执行最少的静态类型检查 价值观。具体来说,任何名称的属性都可以通过 任何值和任何值都可以作为函数调用或 具有任何参数列表的构造函数。

    对象不允许同样的灵活性。

    例如:

    var myAny : any;
    
    myAny.Something(); // no problemo
    
    var myObject : Object;
    
    myObject.Something(); // Error: The property 'Something' does not exist on value of type 'Object'.
    

    【讨论】:

      【解决方案2】:

      Objectany 更严格。例如:

      let a: any;
      let b: Object;
      
      a.nomethod(); // Transpiles just fine
      b.nomethod(); // Error: Property 'nomethod' does not exist on type 'Object'.
      

      Object 类没有nomethod() 函数,因此转译器会生成一个错误,告诉您确切的信息。如果您使用any 代替,您基本上是在告诉转译器任何事情都发生了,您没有提供有关a 中存储的内容的任何信息 - 它可以是任何东西!因此,转译器将允许您使用定义为 any 的内容做任何您想做的事情。

      总之

      • any 可以是任何东西(你可以在上面调用任何方法等而不会出现编译错误)
      • Object 公开了在 Object 类中定义的函数和属性。

      【讨论】:

        【解决方案3】:

        any 是 TypeScript 特有的东西,alex 的回答很好地解释了这一点。

        Object 指的是 JavaScript object 类型。通常用作{} 或有时用作new Objectjavascript 中的大多数东西都与对象数据类型兼容,因为它们继承自它。但是anyTypeScript 特定的,并且在两个方向上都兼容(不基于继承)。例如:

        var foo:Object; 
        var bar:any;
        var num:number;
        
        foo = num; // Not an error
        num = foo; // ERROR 
        
        // Any is compatible both ways 
        bar = num;
        num = bar;  
        

        【讨论】:

        • 你的答案很模糊,并且混合了 TypeScript 中不同类型的 Objectobject
        • @m93a:你能详细说说Objectobject在TS中的区别吗?
        • This 可能是了解差异的最佳来源。主要的一点是object 是所有非原始类型的类型,而Object 是一个包含toString 等常见事物的接口。数字 42 将是 Object,但不是 object
        【解决方案4】:

        与所有类型都派生自“对象”的 .NET 相反,在 TypeScript 中,所有类型都派生自“任何”。我只是想添加这个比较,因为我认为随着越来越多的 .NET 开发人员尝试 TypeScript,这将是一个常见的比较。

        【讨论】:

          【解决方案5】:

          有点旧,但添加一些注释也无妨。

          当你写这样的东西时

          let a: any;
          let b: Object;
          let c: {};
          
          • a 没有接口,它可以是任何东西,编译器对其成员一无所知,因此在访问/分配给它及其成员时不会执行类型检查。基本上,您是在告诉编译器“退后,我知道我在做什么,所以请相信我”;
          • b 具有 Object 接口,因此只有在该接口中定义的成员可用于 b。它仍然是 JavaScript,所以一切都扩展了 Object;
          • c 扩展了 Object,就像 TypeScript 中的其他任何东西一样,但不添加任何成员。由于 TypeScript 中的类型兼容性基于结构子类型,而不是名义子类型,因此 c 最终与 b 相同,因为它们具有相同的接口:Object 接口。李>

          这就是为什么

          a.doSomething(); // Ok: the compiler trusts you on that
          b.doSomething(); // Error: Object has no doSomething member
          c.doSomething(); // Error: c neither has doSomething nor inherits it from Object
          

          为什么

          a.toString(); // Ok: whatever, dude, have it your way
          b.toString(); // Ok: toString is defined in Object
          c.toString(); // Ok: c inherits toString from Object
          

          所以 Object{} 在 TypeScript 中是等价的。

          如果你声明这样的函数

          function fa(param: any): void {}
          function fb(param: Object): void {}
          

          为了接受任何参数的意图(也许你会在运行时检查类型以决定如何处理它),记住这一点

          • fa内部,编译器会让你用param做任何你想做的事;
          • fb 内部,编译器只会让您引用 Object 的成员。

          值得注意的是,如果 param 应该接受多个已知类型,更好的方法是使用联合类型声明它,如

          function fc(param: string|number): void {}
          

          显然,OO 继承规则仍然适用,所以如果你想接受派生类的实例并根据它们的基类型来处理它们,如

          interface IPerson {
              gender: string;
          }
          
          class Person implements IPerson {
              gender: string;
          }
          
          class Teacher extends Person {}
          
          function func(person: IPerson): void {
              console.log(person.gender);
          }
          
          func(new Person());     // Ok
          func(new Teacher());    // Ok
          func({gender: 'male'}); // Ok
          func({name: 'male'});   // Error: no gender..
          

          基本类型是实现它的方法,而不是任何。但那是 OO,超出了范围,我只是想澄清 any 应该只在你不知道会发生什么时使用,而对于其他任何事情你应该注释正确的类型。

          更新:

          Typescript 2.2 添加了一个object 类型,它指定一个值是非原始的:(即不是numberstringbooleansymbolundefined 或@ 987654336@).

          考虑定义为的函数:

          function b(x: Object) {}
          function c(x: {}) {}
          function d(x: object) {}
          

          x 在所有这些函数中都具有相同的可用属性,但使用原语调用 d 会出现类型错误:

          b("foo"); //Okay
          c("foo"); //Okay
          d("foo"); //Error: "foo" is a primitive
          

          【讨论】:

          • 有谁知道为什么他们决定添加{},然后如果他们已经有Object? (反之亦然,以先到者为准)肯定有一些细微差别,对吧?
          • {} 是定义(内联)接口的常规方法,只是在这种情况下,您定义的是没有成员的接口。细微的差别在响应中得到了很好的解释:“{} 扩展了Object,就像 TypeScript 中的其他任何东西一样”。
          • 我想对你投反对票所以,基本上,当你不知道类型时,使用any 并进行运行时类型检查。不要使用any,而是使用您要检查的类型的联合:TypeA|InterfaceB|string。如果您还有未知类型的默认情况,请将{}Object 添加到联合中。
          • Typescript 文档有时会令人困惑,例如 But variables of type Object only allow you to assign any value to them - you can’t call arbitrary methods on them, even ones that actually exist: 让我认为即使调用 toString 也是不允许的,而实际上我认为他们在阅读您的答案后想说 exist at runtime
          【解决方案6】:

          添加到亚历克斯的答案并简化它:

          对象对它们的使用更加严格,因此给程序员更多的编译时间“评估”能力,因此在很多情况下提供更多的“检查能力”并可以防止任何泄漏,而任何是一个更通用的术语和因此可能会忽略大量编译时检查。

          【讨论】:

            猜你喜欢
            • 2017-02-10
            • 1970-01-01
            • 1970-01-01
            • 2016-12-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多