TypeScript Quirks: Undefined vs undefined

Like javascript, typescript has more than one type of undefined / defined… Oh, you didn’t know that? Yeah, it’s kind of crazy.

So in javascript we can have the 2 following kinds of undefined (and possibly a 3rd if you’re creating an array with Array(10)?).

const object1 = {}; // The key "foo" is not defined

const object2 = {
  foo: undefined // The key "foo" has the value undefined
};

This is pretty much the same in TypeScript, but requires 2 different kinds of type definitions.

In the below example we have a stateless React component that takes some content and renders it inside a paragraph.

interface IProps {
  content: string;
}

const Component = ({content}: IProps) => (
  <p>
    {content}
  </p>
);

If we were to do the following, our code would not compile because we have not provided a content prop.

<Component />

So, surely changing the interface to allow content to be undefined should be fine, right?

interface IProps {
  content: string | undefined;
}

Wrong *sad face*. Here we are still saying that we expect a prop called content, but it’s value may be undefined.

<Component /> // Not happy

<Component content={undefined} /> // Happy

What we actually want to do is the following.

interface IProps {
  content?: string; // Note: no more need for "| undefined"
}

This will allow us to create our component in the following ways.

<Component /> // Happy

<Component content="Hello" /> // Happy

<Component content={undefined} /> // Happy

There is no way (that I know of) to say that a value may not be defined, but may not have the value of undefined… though when would you ever really need that?

So, there’s a couple of different undefineds for you, but wait, we’re not done yet.

Say we create a function that doesn’t return anything, like the following.

function doSomething (value) {
  console.log(value);
}

You’d think that we could give this the explicit return value of undefined, because in javascript, this returns undefined.

function doSomething (value): undefined {

Well, in typescript this is wrong. By giving the explicit return value of undefined, we’d actually have to make a return call with the value undefined. What we actually want is to return void.

function doSomething (value): void {

Similarly to many other languages typescript uses a void type to mean that a function literally does not return anything. This comes in handy in a lot of places, including defining callback and or promise types e.g.

type Callback = (event: Event) => boolean | void;

Right, good, now we have undefined, ? not defined, void, and I guess also null. No wait. We’re still not done. Yes, it’s true, there is another kind of undefined.

I bet you’ll NEVER guess what this one is.

Yeah, you’re right… It’s never.

If we define a type like this one:

type EmptyArray = never[];

And assign this to an array:

const thing: EmptyArray = [];

It will ensure that the array is always empty. So we can’t do any of the following:

const thing: EmptyArray = [1];
const thing: EmptyArray = ['1'];
const thing: EmptyArray = [undefined];
const thing: EmptyArray = [null];

thing.push(anything);