Chapter 4: Introduction
Chapter 4: TypeScript Architecture
Chapters - Table of contents

What is TypeScript Architecture?

We covered, in Chapter 1, the TypeScript inference super powers, being able to infer types even on plain JavaScript code.
By adding types to variables, objects and functions (Chapter 2), we are helping TypeScript inferring the proper types, improving the Developer Experience at a low cost.
By investing time in building more flexible function definitions and creating types on top of others using Mapped types (Chapter 3), we are make it easier to catch errors in complex scenarios, bridging the "stability gap" of plain JavaScript.
Mapping of TypeScript features on improving Developer eXperience and stability.
Mapping of TypeScript features on improving Developer eXperience and stability.
However, in order to truly leverage the power of TypeScript to improve stability, we will need more than building complex types, we will need to do some "TypeScript Architecture".
So, what is "TypeScript Architecture" exactly?
TypeScript architecture is the process of adopting the proper TypeScript configuration, setting up the proper linters and development best practices to build stronger types in order to improve the stability of a project.
This last chapter will introduce you to all the tips and architectural tricks to get the best of TypeScript by ensuring that:
  • no place is left to untyped or mistypes data in your application
    (strict mode, data-types generation, ESLint)
  • your applications types are easy to maintain
  • all untyped external dependencies and legacy code are properly incorporated in your application
First, let's review the main challenge of improving stability with TypeScript.

TypeScript types: a "weak" chain of types

TypeScript's main job is to infer types.
When running on a code base, TypeScript is navigate through the AST (_Abstract Syntax Tree - _see below) in order to "guess" the types of all variable, functions and properties.
Example of TypeScript AST preview using https://astexplorer.net/
Example of TypeScript AST preview using https://astexplorer.net/
When doing so, TypeScript can face multiple challenges, let's see the 3 main scenarios:

Dealing with plain JavaScript code

1import { identity } from 'identity-js-package'
2// identity(val) is a plain JavaScript function, not providing type definitions.
3//  TypeScript fallbacks its type to `identity(value: any): any`
4
5const a = 1 // `a` is inferred to be a `number` (constant inference)
6
7const c = identity(a) // `c` should be `number` but is `any`
8
When importing function or variables from a plain JavaScript modules or files, TypeScript will resolve its types to any (as we saw, equivalent to "no type").
The issue is assigning a variable, parameter or return type to any is the equivalent of sending it to the "black hole of types".
any is the equivalent of saying:
From this point of the AST, stop checking for types.
This Chapter will give many tactics to deal with plain JavaScript external modules or legacy code.

Dealing with partially typed code

1import { compareDesc } from 'date-fns'
2// the `date-fns` package is providing TypeScript types.
3//  `compareDesc(a, b)` typing is 
4//  `(dateLeft: Date | number, dateRight: Date | number) => number`
5
6// Developer note: TODO add type constraint
7function customDateSort(items: any) {
8  return items.sort(
9    (a, b) => compareDesc(
10      (a.updatedAt || a.createdAt),
11      (b.updatedAt || b.createdAt)
12    )
13  )
14}
15
16// The typo below (`createdAt` missing) is not raised by TypeScript
17//  because of the `items` of `any` type
18customDateSort([{ updatedAt: '2021-10-21', title: 'My blog post' }])
19
Most developers, facing short deadlines or code hard to types tend-up to put a temporary any along with a comment.
As we saw previously, assigning an any type is breaking the type inference, which is the reason why this Chapter will introduce some practice to avoid using any and how to prevent its usage by leveraging TypeScript configuration options and linters.

Dealing with wrongly typed code

1interface User {
2   id: string
3   first_name: string // typo introduced recently
4   lastName: string
5}
6
7// the typo is gonna ripple in other types
8type UserFormData = Partial<Omit<User, 'id'>> 
9
As we will see in the first page of this Chapter ("Typing API's data"), most front-end application are built around centralized data stores which defined a set of data types (ex: User, Workspace, etc...).
Maintaining those data types manually can introduce many issues such as:
  • outdated typing (regarding the API current implementation)
  • typos (as seen above)
  • partial typing of data (not all API’s data has a corresponding type)
Data types being central to modern front-end application, we will see how to automate their generation.

The journey to a stability with TypeScript

This Chapter will gradually introduce you to all the tools to setup the best TypeScript Architecture for a stable applications, from external data and dependencies typing (API, npm modules and legacy code) to make you existing types stronger (TS configuration, linters and best practices) .
We will first cover the most critical part of any application typing: data types.
Then, we will see how to deal with untyped code and migrate existing plain JavaScript code.
Finally, we will look at more many approaches to make your existing types stronger.
We use cookies to collect statistics through Google Analytics.
Do not track
 
Allow cookies