Home > Back-end >  typescript,check the type of object, typeof get compile error
typescript,check the type of object, typeof get compile error

Time:09-30

with this code

export default class App {
  el: HTMLElement;
  constructor(el: string | HTMLElement) {
    if (typeof el === "string") {
      this.el = document.getElementById(el);
    }
    if (typeof el === typeof this.el) {
      this.el = el;
    }
  }
}

get compile error info:
Type 'string | HTMLElement' is not assignable to type 'HTMLElement'. Type 'string' is not assignable to type 'HTMLElement'.ts(2322)

changed code like as follow ,will get no error info:

export default class App {
  el: HTMLElement;
  constructor(el: string | HTMLElement) {
    if (typeof el === "string") {
      this.el = document.getElementById(el);
    }
    if (el instanceof HTMLElement) {
      this.el = el;
    }
  }
}

i'm confused, they should both get error or both get worked.

CodePudding user response:

typeof can return only undefined, null, boolean, number, bigint, string, symbol, function, and object.

You can see more detail in this docs.

CodePudding user response:

The error is clear, the typeof el returns one of "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" type at runtime.

At TS compiler time, typeof becomes a type guard, TS will narrow the type to string | HTMLElement. But the instance props this.el is just HTMLElement.

You should narrow the type of el to HTMLElement, so you need to check it's not string type.

instanceof type guards are a way of narrowing types using their constructor function.

el instanceof HTMLElement statement will narrow the type of el to HTMLElement which can be assigned to this.el.

class App {
    el: HTMLElement | null = null;
    constructor(el: string | HTMLElement) {
        if (typeof el === "string") {
            this.el = document.getElementById(el);
        }
        if (typeof el === typeof this.el && typeof el !== 'string') {
            this.el = el;
        }
    }
}

TypeScript Playground

CodePudding user response:

You should know the difference between typescript's typeof and javascript's typeof. According to this doc, when you use typeof in an expression context, you are actually using the javascript one. Thus:

if (typeof el === typeof this.el) {
  this.el = el;
}

you end up checking two entities both having the type "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function". To help typescript infer the type correctly, you must use an explicit type in your condition:

if (typeof el === 'object') {
  this.el = el;
}

But in your case, the best way is to use an else statement:

if (typeof el === 'string') {
  this.el = document.getElementById(el);
} else {
  this.el = el;
}
  • Related