简体   繁体   中英

typescript,check the type of object, typeof get compile error

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.

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

You can see more detail in this docs .

The error is clear, the typeof el returns one of "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" "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 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

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" "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" "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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM