Advanced TypeScript
You rarely learn Advanced TypeScript features just by themselves. Only when combined with other parts of the language and put in context they reveal their true power. And this is the focus of this guide.
This is a constantly updated collection of articles you can find on this site. Clustered by use-cases, detailing which technologies you use to achieve your goal.
While each article stands on its own I can recommend reading it like a book, as you see familiar concepts in a new light.
Ready? let’s go!
Last update: May 11, 2022 at 28.000 words!
Table of contents #
- TypeScript and JavaScript: 6 articles
- Control flow: 3 articles
- Ambient declarations: 4 articles
- Working with generics: 4 articles
- Pitfalls and workarounds: 5 articles
TypeScript and JavaScript #
TypeScript is a strict superset of JavaScript, and you can feel that with every line of TypeScript you write. I wrote a couple of articles looking at concepts in JavaScript and how they influenced the inner workings of TypeScript.
Boolean in JavaScript and TypeScript #
Boolean is a very boring type, but there’s actually a lot to it, especially if you want to learn how the type-space in TypeScript works.
You learn:
- Union types
null
andundefined
as types- Value types (or literal types)
Symbol in JavaScript and TypeScript #
Symbols are a very unique type in JavaScript, as every created symbol can only exist once. TypeScript even has a keyword for that:
You learn:
- How Symbols work
- The
unique
keyword - Run-time
enums
!
this in JavaScript and TypeScript #
Sometimes when writing JavaScript, I want to shout “This is ridiculous!”. But then I never know what this
refers to. All about this
and how to type it.
You learn:
this
!this
parametersThisParameterType
,OmitThisParameter
,ThisType
helpers
void in JavaScript and TypeScript #
void
is a very special case of undefined, that not only exists in TypeScript, but also in JavaScript!
You learn:
- The relation of
undefined
andvoid
, and how it stems from JavaScript - A bit on substitutability
Substitutability #
Substitutability is a concept in TypeScript that makes sure that functions that are passed as values are type-safe even though the signature is not 100% the same.
You learn:
- Substitutability for
void
- Substitutability for functions with different function signatures
The constructor interface pattern #
Classes in JavaScript are little more than syntactic sugar for the old prototype and constructor function pattern that exists for ages. That’s why TypeScript also needs two types to describe classes!
You learn:
- Two types for classes: Constructor function and prototype
- The
new
keyword in types
Control Flow #
Control flow is one of the biggest concepts in TypeScript. TypeScript will take all the type information and all your branching statements (if
and switch
) to figure out what type your variables have at a certain part in your code. You can influence control flow.
Type predicates #
Type predicates are custom type guards where you can decide to make the type of your input more concrete. We look at an easy example to see what narrowing down means.
You learn:
- Custom type guards
- Union types
Type predicates for hasOwnProperty #
We create a custom hasOwnProperty
function that changes the shape of the current object significantly!
You learn:
Records
- Type predicates
unknown
type
Assertion signatures #
Assertion signatures are similar to type predicates, but they work outside branching statements. In this example, we create our own defineProperty
function where we can add properties to the type we originally defined.
You learn:
- Conditional types
- Assertion signatures
- Property Descriptor
Unexpected intersections #
There are situations where you write regular, working JavaScript, but get errors thrown at you! They bring some funny intersection types along, where you might wonder what they mean. This article sheds some light on it.
You learn:
- Index access types safe-guards
- Function type unions
- Binding generics
Ambient declarations #
TypeScript has a ton of built-in types, all describing what’s going on in the world of JavaScript. But what if something is missing? We can declare our environment without having the actual code to it. This is what we do in this example.
Improving Object.keys #
This is a direct continuation of the last two examples in the last chapter. This time, we posh up Object.keys
a little, and we are not creating a helper function, but patch the original ObjectConstructor
.
You learn:
- Conditional types
- The
keyof
operator - The
ObjectConstructor
interface - Interface declaration merging
Array.prototype.includes on narrow types #
Similar to the two above, you are going to check if you can modify Array.prototype.includes
to work in situations where your array is alrady very narrow!
You learn
- Interface declaration merging
- Type predicates
- Type assertions
Ambient file modules #
What if the file you import isn’t a JavaScript or TypeScript file? This can happen in Webpack, for example. Thankfully, TypeScript has a way to describe any file and which types to expect.
You learn:
- Wildcard module declarations
- Module declarations for SVG, CSS, MDX, and more!
Extending JSX Elements #
What if you need to use a web component in JSX, but you get type errors because React doesn’t know about the components you use? You can extend the React types that you import with the information for your environment.
You learn:
- Module re-declarations
- Namespace declaration merging
- Interface declaration merging
Augmenting global #
Type information for all the DOM APIs and window
is stored in the global object. If we miss something, we can add info to the global
namespace. We do this by adding a DOM API that will appear at some time in TypeScript once it’s stable enough: Resize Observer.
You learn:
- WIDL
- The
global
namespace
Working with Generics #
Generics are immensely powerful in TypeScript, especially combined with conditional types. Here we look at some
Type maps #
Type maps are a container type that contains a set of key-value entries that are very similar to plain JavaScript objects. Together with index types and mapped types, we can have a great lookup table!
You learn:
- Index types
- Type maps
- Conditional types
Match the exact object shape #
TypeScript is a structural type system, which means that as long as all required properties of an object are available and have the correct type, TypeScript is happy. This can lead to some side effects if there are excess properties. Rarely, but possible! We work on a helper type that gets rid of excess properties.
You learn:
- Conditional types
never
typeExclude
Variadic tuple types #
Variadic tuple types are a generic type pattern where you can define a sub-set of a tuple type in a generic type variable. What does that even mean? We take a good look at it in this article.
You learn:
- Tuple types
- Variadic tuple type generics
- Conditional types
Union to Intersection type #
There are some cases where you need to transform a union type to an intersection type. We see how we can use distributive conditional types and contra-variance to do so.
You learn:
- Union and intersection types
- Distributive conditional types
- Co-variance and Contra-variance
Pitfalls and workarounds #
Sometimes the type system doesn’t work as you think it should. There’s usually a good reason behind that.
The humble function overload #
The type system can be very complex. In some scenarios, some more traditional means can lead you to better goals than to use the latest and greatest features
You learn:
- Conditional types
- Variadic tuple types
- When to make good use of function overloads
Unexpected intersections #
You try to do something in TypeScript that would work in JavaScript, but for some weird reason you get a type that is never
or some other intersection that just doesn’t make sense. How can you work around this?
You learn:
- Generics
- Index access
Array.includes on narrow types #
Say you know exactly which values to expect. Now you want to check if some values from a broader set are part of it. This should work with Array.includes
, except that it doesn’t.
You learn:
- Union types
- Type predicates
- Generics
Iterating over objects #
Why can’t I just use Object.keys
to access my object’s properties? There are several reasons. Let’s check them out.
You learn:
- for-in loops
- Generics
Typing catch clauses #
Your app throws an error, and you want to catch it. You know that only one error type can happen, still TypeScript insist it should be any
or unknown
. What’s the deal?
You learn:
- Error handling