简体   繁体   中英

TypeScript how to enforce a type of multiple type options, Property 'X' does not exist on type 'Y'

In a data structure which is just an object, the keys are strings and the values can be another object or false ( {} or false ), iterating through the values of the data structure and checking if it's an object and then mutating the nested data structure, it still errors, I assume because it could be a boolean - Property 'X' does not exist on type 'boolean | Y'. Property 'X' does not exist on type 'boolean | Y'. What is the best way to fix this? Example below:

type Definition = {
  [key: string]: string;
};

type Dictionary = {
  [word: string]: Definition | boolean;
};

function checkWorkds(words: Dictionary) {
  for (let [key, val] of Object.entries(words)) {
    if (val !== false) {
      val['etymology'] = "idk"; // <--- Error here :sob:
    }
  }
}

const dict: Dictionary = {
  hello: {
    name: "hello",
    language: "english"
  },
  bob: false,
  hola: {
    name: "hola",
    language: "spanish"
  }
};

checkWorkds(dict);

The exact error in the example above is

Property 'etymology' does not exist on type 'true | Definition'.
  Property 'etymology' does not exist on type 'true'.

It seems that if (typeof val !== 'boolean') { seems to work, however I was curious if there is an alternative/The Right Way as this is a trivial example and in the production code we have lots of nested values that can either be other objects or false .

boolean type has true and false . Checking whether val !== false isn't enough; only false is eliminated, so there is still Definition | true Definition | true left. You'll need to...

either (1) adjust Dictionary type to have only false value if you only use this Boolean value

type Dictionary = {
  [word: string]: Definition | false;
};

or (2) check val !== false && val !== true or typeof val !== 'boolean' so that there are no more boolean possibilities left in the union.

function checkWorkds(words: Dictionary) {
  for (let [key, val] of Object.entries(words)) {
    if (typeof val !== 'boolean') {
      val['etymology'] = "idk"; // <--- no more error
    }
  }
}

Instead of val !== false , you should be comparing the type using typeof , this way typesript will know for sure that within the if clause has nothing to do with boolean

Playground

For checking the exact type you want to have, use an equal operator so you won't have any issue if you add more types to Dictionary in the future.

function checkWorkds(words: Dictionary) {
  for (let [key, val] of Object.entries(words)) {
    if (typeof val === 'object') { // <--- Instead of typeof val !== 'boolean'
      val['etymology'] = "idk";
    }
  }
}

Ex: Checking type if !== you will be having type error if adding string to the union:

type Dictionary = {
  [word: string]: Definition | boolean | string;
};

在此处输入图像描述

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