Thinking in TypeScript

Christian Gonzalez
Sep 19, 2017 · 5 min read

On the Office Online team, we regularly hire experienced engineers that have never worked on large scale web applications. As a result, we have a large number of engineers with strong backgrounds in languages like C# and Java learning how to write code in TypeScript for the first time. This transition comes naturally to most engineers, as some of the syntax may feel very familiar to C# and Java developers, but I think there is a lot to be gained from spending some time to learn how to leverage some of the unique capabilities of the language. This blog post will focus on some of the tips we’ve often found ourselves sharing in code reviews for developers that are new to TypeScript. I hope you find them helpful!

You might not need a class

While this is a perfectly reasonable way to organize your code, you could instead create a module that exports a set of utility functions:

While it is nice that the utility function is less verbose and generates less JavaScript when transpiled to ES5, this isn’t the primary reason why we prefer to use functions over classes in many situations. By favoring functions over classes, developers will naturally be writing code that adheres to the principle of Composition over Inheritance, which we’ve found makes it easier for us to write components that are testable and loosely coupled.

An interface might not be what you expect it to be

While this is perfectly valid TypeScript, we rarely ever write code that looks like this inside the Office Online codebase. If you read the TypeScript documentation for interfaces, you’ll see them described as a way to define the types of a JavaScript object rather than something that should be implemented by a class. This means we could actually write code that looks like this:

Now, this code is fundamentally different than the code in the previous example. The prior example created an instance of a class, which has a constructor and could also have methods, and assigned it to a person variable. The second example simply created a plain JavaScript object and assigned it to the person variable. When following the second approach, developers will typically use pure functions to manipulate these plain JavaScript objects rather than having methods to manipulate the state contained within the person object. This approach allows for a clean separation of data and the code that manipulates data, which is something I’ve found makes code easier to reason about and unit test.

You may have noticed that these first two guidelines have recommended that you avoid using classes. While I personally prefer plain JavaScript objects manipulated by pure functions over classes with methods, this does not mean I think you shouldn’t use classes at all in TypeScript. In fact, I actually encourage them to be used for things like stateful React components. These recommendations are mostly about demonstrating the new possibilities a developer has for structuring their code when introduced to a language that has first-class functions.

The types don’t exist at run time

While the inability to access type information at run time may seem like a deal-breaking constraint, TypeScript supports Discriminated Unions as a mechanism for differentiating objects of different types at run time. To better understand how discriminated unions work, let’s consider an application that displays a number to the user and supports a set of actions that manipulates that number.

In this example, we have a function getNextState that takes in an Action and the current state and returns the next state. Action is a union type of the Add and Decrement interfaces. Both of these interfaces have a type property, referred to as the discriminant, that allows us to determine which Action type was passed in to the getNextState function.The TypeScript compiler is able to leverage this type property within each clause of the switch statement to narrow down the set of valid properties to just those that correspond to the interface with that type value. For example, the compiler knows that the action inside the ‘Add’ case has a numberToAdd property and it knows that any reference to numberToAdd inside of the ‘Decrement’ block is a compiler error. The use of a discriminant allows us to differentiate objects of different types at runtime while also providing us with stronger type checking and an improved intellisense experience. When discriminated unions are combined with TypeScript strict mode, the compiler is able to do exhaustiveness checking on the switch statement inside the getNextState function, which is helpful to ensure that developers update that function as new Action types are added.

Use undefined instead of null

with

Since both null and undefined are falsy values. However, this approach won’t work if the type of foo also had valid falsy values (such as 0 for a number or “” for a string) that you don’t want to handle in the same fashion as null and undefined. As a result, we found it preferable on the Office Online team to avoid using null in our codebase, instead encouraging the use of undefined (almost) everywhere.

Conclusions

Web Dev @ Microsoft

A place for developers from across Microsoft to share ideas…

Thanks to Kyle Ryan

Christian Gonzalez

Written by

Software Engineer working on Fluid Framework at Microsoft

Web Dev @ Microsoft

A place for developers from across Microsoft to share ideas and best practices

Christian Gonzalez

Written by

Software Engineer working on Fluid Framework at Microsoft

Web Dev @ Microsoft

A place for developers from across Microsoft to share ideas and best practices

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store