TypeScript Gotchas

edbentley

Ed Bentley

Posted on March 14, 2020

TypeScript Gotchas

TypeScript can be a great language to work with. If you're starting a new mid to large project in JavaScript, I would certainly recommend using TypeScript at the moment. Knowing your code is correctly typed brings a lot of confidence when it comes to making changes.

However in order to get this great experience, I always have a few "gotchas" in the back of my head while writing TypeScript. These are things to watch out for, which can cause runtime issues if you're not careful.

This can provide us with a "sound" codebase, even though TypeScript is inherintly an "unsound" type system.

These examples have been tested with TypeScript v3.8.3

1. Beware JSON.parse and .json()

const obj = JSON.parse('{ "x": 5 }');

obj.hello(); // uh-oh! obj.hello is not a function
Enter fullscreen mode Exit fullscreen mode
const data = await fetch("https://pokeapi.co/api/v2/pokemon/1/").then(res => res.json());

data.hello(); // same again!
Enter fullscreen mode Exit fullscreen mode

Here obj and data are returning the type any, even in strict mode, and so TypeScript doesn't warn you about these runtime errors.

Solution: you should decode anything that you don't know the type of. I recommend bringing in a library like io-ts for the job. It's also really useful for query parameters.

2. Beware record types

type MyObj = Record<string, string>;

const myObj: MyObj = {};

const result = myObj.hello;
Enter fullscreen mode Exit fullscreen mode

What's the type of result? TypeScript tells me it's string, but actually it's undefined!

I still find Record to be useful in some cases but you really need to be careful with it. You could also consider using something like fp-ts lookup in order to be extra careful.

3. Beware type assertions

type MyObj = { hello: () => void };

const myObj = {} as MyObj;

myObj.hello(); // uh-oh! myObj.hello is not a function
Enter fullscreen mode Exit fullscreen mode

Just avoid as and angle bracket type assertions as much as you can.

4. Beware catch

try {
    throw undefined;
}
catch (e) {
    e.hello(); // uh-oh! Cannot read property 'hello' of undefined
}
Enter fullscreen mode Exit fullscreen mode

Here e has type any so no type errors are reported. Interestingly if you try to annotate e like

catch (e: Error) {
Enter fullscreen mode Exit fullscreen mode

TypeScript won't let you do that which is good. But without it it's still returned as any. 🤷

Watch out for .catch on a Promise too.

5. Don't use any or !

By now this should go without saying. Using any breaks down the point of bringing in TypeScript and you loose all of your confidence everything is sound and runtime error free.

! can be very convenient but it's best avoided. My only exception is in test code.

Avoid things like this

function lowercaseOptional(val?: string) {
    return val!.toLocaleLowerCase();
}
Enter fullscreen mode Exit fullscreen mode

and prefer explicitly handling the undefined case like this

function lowercaseOptional(val?: string) {
    if (!val) return "";
    return val.toLocaleLowerCase();
}
Enter fullscreen mode Exit fullscreen mode

You can ensure any and ! aren't used by setting up the eslint rules no-explicit-any and no-non-null-assertion.

6. Be careful with libraries!

There are some libraries which served their purpose brilliantly in JavaScript. But in TypeScript, it's simply not feasible to keep using the same API while also keeping your code sound.

This example is taken straight from the lodash doc and converted to TypeScript:

function square(n: number) {
  return n * n;
}

var addSquare = _.flow([_.add, square]);
addSquare(1, 2);
Enter fullscreen mode Exit fullscreen mode

What's the return type of addSquare? any ! 😩

Honourable mention - arrays

const array: string[] = [];
const val = array[1];
Enter fullscreen mode Exit fullscreen mode

TypeScript tells us val is of type string, when really it's undefined. However this is a gotcha in most programming languages, and it really wouldn't be practical to check for optionals in something like a for loop. But it's good to be aware of.

Do you have any more "gotchas" I'm missing? Please share in the comments below!

💖 💪 🙅 🚩
edbentley
Ed Bentley

Posted on March 14, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related