【问题标题】:Type Object includes string?类型对象包括字符串?
【发布时间】:2021-07-03 06:57:10
【问题描述】:
function isObject(v: any): v is Object{ 
    return v instanceof Object && !Array.isArray(v);
}


let v: string | Object;
if (isObject(v))
    v.hasOwnProperty("x");
else
if (typeof v === 'string')
    v.trim();             //Error: Property 'trim' does not exist on type 'never'

我对最后一行中的错误感到困惑,显然,v 被缩小为输入“从不”,但我看不出它的逻辑。 (打字稿版本 4.2.3)

【问题讨论】:

  • 在类型位置使用object(不是Objecttypescriptlang.org/play?#code/…
  • 有很多方法可以改进这段代码。但我想他得到的这个错误是因为他的 if 和 else 是错误的。在这种情况下,他不需要其他东西。
  • 为什么需要在单个变量中包含字符串和对象?

标签: typescript typeguards


【解决方案1】:

我认为这种看似奇怪的行为的解释是object != Object。而 object 是一种表示所有非原始类型(不是字符串)的类型,而 Object 类型只是一个接口,其中包含围绕 javascript 对象的常用方法,如 toString() 等。

在函数签名中有:

v is Object

这只会检查您的变量类型是否实现了Object 接口的所有方法。实际上对于string,情况就是这样,因此 Typescript 认为:

等等,他给我提供了一个变量Objectstring,它们都实现了Object 接口,因此该方法每次都会返回true。这就是为什么在 if 的 else 情况下它是 never

如果您使用object 而不是Object,这将得到解决,因为object 是代表所有非原始类型(不是string)的类型。因此,typescript 并不认为你的函数会像 Object 那样一直返回 true。

【讨论】:

    【解决方案2】:
    const a: Object = '1'; // OK
    const b: Object = 1; // OK
    const c: Object = false; // OK
    const d: Object = {}; // OK
    const e: Object = undefined; // Error
    const f: Object = null; // Error
    
    const g: object = '1'; // Error
    
    type T1 = string extends Object ? boolean : number; // boolean
    type T2 = Number extends Object ? boolean : number; // boolean
    ...
    type T3 = undefined extends Object ? boolean : number; // number
    type T4 = null extends Object ? boolean : number; // number
    

    也就是说,Object 是 ONLY 定义的成员的类型。 并且每个类型都扩展了 Object 除了 undefined 和 null

    所以

    v is Object ===> v is object

    【讨论】:

      【解决方案3】:
      let v: string | Object;
      

      在执行 instanceOf(type checker) 时,将 v 变量类型视为 string,因为您提到 string 作为第一种类型,而 Object 是该变量的第二种类型。那么在这种情况下,没有该变量的任何值,instanceOf 如何知道类型?所以它会检查null instanceof Object。这意味着 null 不是对象类型。这就是 isObject() 返回 false 的原因。见

      console.log(null instanceof Object)

      如果您分配任何值,则只有 instanceOf 将被视为基于值的类型,因为该变量具有 两种 数据类型。

      【讨论】:

        【解决方案4】:

        Object 接口在 typescript 中是这样定义的:

        interface Object {
            constructor: Function;
            toString(): string;
            toLocaleString(): string;
            valueOf(): Object;
            hasOwnProperty(v: PropertyKey): boolean;
            isPrototypeOf(v: Object): boolean;
            propertyIsEnumerable(v: PropertyKey): boolean;
        }
        

        几乎任何类型,包括像string 这样的原语都可以分配给Object(是的,字符串具有上述所有属性)。

        object(小写)是表示非原始类型的类型,即任何不是numberstringbooleansymbolnullundefined

        function isObject(v: any): v is object {
            return v instanceof Object && !Array.isArray(v);
        }
        
        declare let v: string | object;
        if (isObject(v))
            v.hasOwnProperty("x");
        else
            v.trim(); // v narrowed to string
        

        Playground

        Do's and Don'ts

        【讨论】:

          猜你喜欢
          • 2011-04-10
          • 1970-01-01
          • 1970-01-01
          • 2011-10-20
          • 2011-11-08
          • 2021-08-25
          • 2018-05-06
          • 2020-12-08
          • 1970-01-01
          相关资源
          最近更新 更多