Almost vegan food: Veggies with noodles and rice

I posted the image above on Twitter with the caption “Almost vegan”—as a (bad) joke about how something cannot be “almost vegan”. Peter Kofler answered “Almost pregnant”, which made me think of… programming, of course. Types, in particular.

Some food either is vegan, or it is not. Something that is almost vegan is still not vegan. Like the food I cooked: It looks like it might be vegan, but the noodles contain a bit of egg, so it isn’t.

One might argue that the food pictured here is more vegan than e.g. steak and potato skins, with all the cheese and bacon and beef—i.e. that there are different shades of true and false. Let’s ignore that for now—It would take us into the realm of fuzzy logic; A topic that I might explore somewhere around part 97 of this series, if I ever get that far.

In typescript, you would say that the property—whether something is vegan or not—is of type boolean:

const vegan: boolean = false

The type boolean can only hold a finite set of values. true and false, and also null and undefined in the default configuration (where null and undefined are two different ways of saying “I don’t know”). Or, in Roster notation and as an Euler diagram:

boolean = { true, false, null, undefined }

The set of boolean values: true, false, null, undefined

All the types in TypeScript describe a set of possible values. You can imagine them to be sets like your maths teacher explained them to you back when you talked about set theory.

So, a variable of type boolean, like vegan from our first code snippet, can hold any value from this set, but nothing else. Changing the code like below leads to a compiler error:

const vegan: boolean = 0.9 //ERROR
//Type 'number' is not assignable to type 'boolean'.(2322)

We can create a smaller set of possible values by creating a type that can only ever have the value true

type MyTrue = true
const b1: MyTrue = true
const b2: MyTrue = false //ERROR
//Type 'false' is not assignable to type 'true'.(2322)

A new type: MyTrue with values true, null, undefined

In the default configuration, null and undefined are part of every set.

const b3: MyTrue = undefined
const b4: MyTrue = null

But most of the time, this is not what we want. It is just too permissive and prevents us from catching errors early. Imagine asking “Is this dish vegan?” and the waiter answers “null”. I guess that, whatever was the reason for your question, this is not an answer you can accept.

So, let’s turn on strict mode in tsconfig.json and try again…

const b3: MyTrue = undefined //ERROR
//Type 'undefined' is not assignable to type 'true'.(2322)
const b4: MyTrue = null //ERROR
//Type 'null' is not assignable to type 'true'.(2322)

Much Better! booleans, and all other data types, now too have null and undefined removed from their sets of possible values—null and undefined now form their own sets.

Strict mode: null and undefined form their own sets and are removed from every other set

And that is enough for today. In the next installment, I want to write about what it means when you want a boolean that could also be null and/or undefined in strict mode.