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);