Navigate back to the homepage
📚 Books

TypeScript 3 - What you might have missed

Mark Pollmann
January 9th, 2020 · 1 min read

TypeScript has quite the fast release cycle so it’s easy to miss some of their nice features. Here are some of the things I missed when they came out.

Optional Chaining extra goodies (3.7)

JavaScript will get optional chaining soon so the Microsoft team implemented it in TS as well.

I’m sure you know the basics already:

1foo?.bar?.baz // returns undefined if foo or bar is nullish (null or undefined).

That means you can replace code that looks like this:

1if (foo && foo.bar && foo.bar.baz)

with this

1if (foo?.bar?.baz)

But there’s two more things that are easy to miss:

Optional Property Access

This is handy if you want to access a property of an optional array:

1const arr = [{ a: 1 }]
2arr[0].a // ❌ this would throw if arr is not an array
3arr?.[0].a // ✅ 😎

Optional Call

This does what you would expect, call the function if it’s a callable, else return undefined. This is useful if you have an optional function parameter in a function, for example.

1function f() {}
2const g = null
3
4f() // ✅
5f?.() // ✅
6
7g() // ❌ throws
8g?.() // ✅ returns undefined

Assertion Functions (3.7)

This lets you write your own assertion functions you might know from Node and typecheck properly.

1// example function from docs
2function assertIsDefined<T>(val: T): asserts val is NonNullable<T> {
3 if (val === undefined || val === null) {
4 throw new AssertionError(
5 `Expected 'val' to be defined, but received ${val}`
6 );
7 }
8}
9
10const result: Array<Number> | null = await getStuffFromService()
11result.map(...) // ❌ undefined is not a function
12assertIsDefined(result)
13result.map(...) // ✅

Const Assertions (3.4)

One thing tripping up new JavaScript developers is that the const keyword doesn’t create a constant for reference types (like objects and arrays). Only the binding to the variable is not allowed. Let’s look at an example:

1const myObject = { a: 1 }
2myObject = { d: 1 } // ❌ This is trying to bind the myObject variable to a new object and is not allowed
3
4const myObject = { a: 1 }
5myObject.b = 2 // ✅ This is allowed in JavaScript!

TypeScript actually shows an error here, since it infers the type as having exactly one attribute: a.

TypeScript doesn’t complain when trying to change existing attributes, though:

1const myObject = { a: 1 }
2myObject.a = 2 // ✅

The same is true for arrays:

1const myArray = [1, 2, 3] // inferred type is number[]
2myArray.push(4) // ✅ allowed!

What if you want to have a real, read-only constant? Here the new const assertions come to the rescue:

1const myObject = { a: 1 } as const // inferred type is now {readonly a: 1}
2myObject.a = 2 // ❌ Error!
3
4const myArray = [1, 2, 3] // inferred type is now readonly [1, 2, 3]
5myArray.push(4) // ❌ Error!

The unknown type (3.0)

The new unknown type is designed to be the type-safe version of the dreaded any type. In particular, we can not run any operation on it without any type checking beforehand. An example:

1let value1: any
2value1.a.b.c.d // ✅ allowed
3value1.toString() // ✅ sure!
4value1() // ✅ go ahead
5new value1() // ✅ be my guest
6
7let value2: unknown
8value2.a // ❌ nope
9value2.toString() // ❌ nope again
10value2() // ❌ still nope
11new value2() // ❌ nice try

When would this be useful? Think about working with results from API calls or de-serializing a value from localStorage:

1const item = localStorage.getItem(someKey) // '1.2345'
2const value: unknown = JSON.parse(item) // could be anything
3
4value.toFixed(2) // ❌ not allowed. Would throw if item wasn't set in localStorage
5
6if (typeof value === 'number') {
7 value.toFixed(2)// 1.23
8}

Conclusion

TypeScript gets better and better and sometimes it’s hard to keep up to date. I hope that this short write-up might be helpful for some of you.

More articles from Mark Pollmann

Startup Sales

How to get your first customer as an introverted techie.

December 4th, 2019 · 4 min read

An Introduction to Docker for NodeJS

The Why, the How and the What Next of dockerizing your application.

November 12th, 2019 · 4 min read
© 2017–2021 Mark Pollmann
Link to $https://twitter.com/MarkPollmannLink to $https://github.com/MarkPollmannLink to $https://www.linkedin.com/in/mark-pollmann-961446132/