最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why TypesScript allows an invalid comparison - boolean === undefined? - Stack Overflow

programmeradmin4浏览0评论

Faced with the strange behavior of TS.

const isItLanding = false;

if (isItLanding === undefined) { // valid
  return ...;
}

But here

const isItLanding = 1;

if (isItLanding === 'undefined') { // error
  return ...;
}

Why doesn't TS insure against writing invalid parisons? And how can I change this behavior?

My TS config looks like:

{
  "pilerOptions": {
    "strict": true,
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "importsNotUsedAsValues": "error",
    "allowSyntheticDefaultImports": true,
    "incremental": true,
    "tsBuildInfoFile": ".next/cache/.tscache/",
    "jsx": "preserve",
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["src/*"],
      "test-utils": ["./src/client/test-utils"]
    }
  },
  "exclude": ["node_modules", "cypress"]
}

Faced with the strange behavior of TS.

const isItLanding = false;

if (isItLanding === undefined) { // valid
  return ...;
}

But here

const isItLanding = 1;

if (isItLanding === 'undefined') { // error
  return ...;
}

Why doesn't TS insure against writing invalid parisons? And how can I change this behavior?

My TS config looks like:

{
  "pilerOptions": {
    "strict": true,
    "target": "esnext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "importsNotUsedAsValues": "error",
    "allowSyntheticDefaultImports": true,
    "incremental": true,
    "tsBuildInfoFile": ".next/cache/.tscache/",
    "jsx": "preserve",
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "~/*": ["src/*"],
      "test-utils": ["./src/client/test-utils"]
    }
  },
  "exclude": ["node_modules", "cypress"]
}
Share Improve this question edited Nov 22, 2022 at 12:09 coolswood asked Nov 22, 2022 at 11:34 coolswoodcoolswood 1411 silver badge8 bronze badges 6
  • 1 What does your tsconfig look like? You probably don't have some strict setting enabled. – yuriy636 Commented Nov 22, 2022 at 11:37
  • whether strict setting is enabled or not, he should not get the first two results as valid. or is that possible? – Nishant Commented Nov 22, 2022 at 11:41
  • 2 Whether or not the parison is permitted has no effect on type safety in these cases. The piler still narrows the type of the value to never in the resulting truthy code branch: tsplay.dev/w17jGm – jsejcksn Commented Nov 22, 2022 at 11:51
  • @jsejcksn Looks very bad, and there is no solution? – coolswood Commented Nov 22, 2022 at 11:54
  • ^ @coolswood If you don't want to permit certain syntax in your code, that's the job of a linter. There's no type safety issue here. – jsejcksn Commented Nov 22, 2022 at 11:57
 |  Show 1 more ment

3 Answers 3

Reset to default 9

Short answer: TypeScript intentionally allows any type to be pared to "null" or "undefined"

It is allowed because boolean can be undefined

In TypeScript boolean can hold four values true, false, undefined and null, what means that by definition there might be a case where the parison will in fact be true.

let bool: boolean = true;
bool = false;
bool = null;
bool = undefined;
//All piles without an issue

if(bool === undefined){
   console.log("You will see me!");
}

How to ensure that boolean can only be true or false?

In your TS config you can set a flag strictNullChecks to true, this way when type is checked both undefined and null will be taken into account. Once this flag is set, the code above will return an error.

let bool: boolean = true;
bool = false;
bool = null; //Error > Type 'null' is not assignable to type 'boolean'.
bool = undefined; //Error > Type 'undefined' is not assignable to type 'boolean'.

Why after changing the flag parison to null or undefined is still allowed?

Consider the code below:
const bool: boolean = false;

if(bool === undefined){
   console.log("I am undefined!");
}
if(bool === null){
   console.log("I am null!");
}

console.log("It piled?");

Why neither of these if statements return an error, even if they are always false?

The answer might be disappointing to some, but the reason is simple: It is intentionally designed that you can pare any type to "null" or "undefined". It's the way the language was constructed, that is to allow defensive programming. It might be changed in the future, if there is enough of demand, but I personally don't think there ever will be.

if(12 === undefined){
   console.log("impossible isn't it?");
}
if("ab" === null){
   console.log("no way it will ever be true!");
}
if(false === undefined){
   console.log("never ever");
}

/*
if(12 === "ab") 
^this would error as parison to different types is allowed only with null and undefined
*/

console.log("Yet, it will indeed pile");

I found the right rule in the linter at https://typescript-eslint.io/rules/no-unnecessary-condition. This pletely solves the problem!

You can then use it in your eslint.config.mjs file like:

// @ts-check

import eslint from "@eslint/js"
import tseslint from "typescript-eslint"

export default tseslint.config(
    eslint.configs.remended,
    tseslint.configs.remendedTypeChecked,
    {
      languageOptions: {
        parserOptions: {
          projectService: true,
          tsconfigRootDir: import.meta.dirname,
        },
      },
    },
    {
        rules: {
            "@typescript-eslint/no-unnecessary-condition": "error",
            // Other rules e.g. ...
            "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_$" }],
        },
    },
)

You will need to have the following packages installed:

  • @eslint/js
  • @typescript-eslint/eslint-plugin
  • eslint
  • typescript
  • typescript-eslint

If you are using Visual Studio Code then you can also install the eslint extension to get these errors to show in your IDE.

This behavior is intentional. See discussions about it at #14764 or #11920.


In short: Checking if something is undefined or null is needed for the sake of "defensive programming".

One should be able to test inputs to be valid to when values might be ing from non-TypeScript users.

Consider a function like this:

function fn(x: string) {
  if (x === undefined) throw new Error('x cannot be undefined');
}

Its entirely possible that someone using JavaScript would call this function with a value that might be undefined. Having a pile time error disallowing the parison would be annoying.

发布评论

评论列表(0)

  1. 暂无评论