
TypeScript 4 Design Patterns and Best Practices
By :

You now know what libraries are included in the code examples and how to run them. Just as it is important to know how to use the examples in this book, it is of equal importance to master the editor and the development environment. This is because using an Integrated Development Environment (IDE) can help you maximize your time when you're debugging or refactoring methods or functions.
First, you will learn how to use VSCode for this book's code. This will help you not only run and debug the examples, but experiment with the code as well. You can use the IDE's inspection utilities to view the inferred types of each defined variable. Finally, you want to understand how to refactor existing code so that you can make it easier to read and reuse.
VSCode is a lightweight integrated editor that was released in 2015 by Microsoft. It offers an impressive array of features that aid us when writing code. It currently supports several major programming languages, including TypeScript, Java, Go, and Python. We can use VSCode's native TypeScript integration to write and debug code, inspect types, and automate common development tasks. Let's get started:
Chapter 1
folder and inspect the programs located there.Figure 1.1 – Run Code from Chapter 1 option
computeFrequency.ts
. This contains a function that computes the frequency Map
of an input string:function computeFrequency(input: string) { const freqTable = new Map(); for (let ch of input) { if (!freqTable.has(ch)) { freqTable.set(ch, 1); } else { freqTable.set(ch, freqTable.get(ch) + 1); } } return freqTable; } console.log(computeFrequency("12345"));
The result will be shown in the console:
Map(5) {1 => 1, 2 => 1, 3 => 1, 4 => 1, 5 => 1}
Figure 1.2 – Debugging code
.vscode/launch.json
file and modify the inputs-> programNameChapter1->
options to include an additional filename. For example, if you have created a new file named example.ts
, you will need to change the inputs
field so that it looks like this:"inputs": [ { "type": "pickString", "id": "programNameChapter1", "description": "What program you want to launch?", "options": [ "computeFrequency.ts", "removeDuplicateVars.ts", "example.ts", ], "default": "computeFrequency.ts" } ]
From now on, you will be able to select this program from the launch list.
Now that you know how to run and debug programs using VSCode, you probably want to know how to inspect types and apply suggestions to improve consistency.
By default, when you write statements in VSCode, they retrieve suggestions and other operations from the TypeScript language server. This server is bundled together with the tsc compiler and offers an API for querying or performing those refactorings. You don't have to run or configure this server manually as VSCode will do that for you.
Let's learn how to inspect types using VSCode:
removeDuplicateChars.ts
file in the editor. This contains a function that accepts an input string and removes any duplicate characters. Feel free to run it and inspect how it works:function removeDuplicateChars(input: string) { const result: string[] = []; // const result = []; let seen = new Set(); for (let c of input) { if (!seen.has(c)) { seen.add(c); result.push(c); } } } console.log(removeDuplicateChars("aarfqwevzxcddd"));
result
variable:Figure 1.3 – Inspecting the type of a variable
This is fairly obvious as we declared its type. However, we can inspect types that have been inferred by the compiler and figure out when or why we need to add explicit types.
What happens when you don't explicitly add types to variables that need them? In most cases, the compilation will fail.
const result = [];
removeDuplicateVars.ts:8:19 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'.
If you inspect the type again, you will see that TypeScript will infer it as never[]
:
Figure 1.4 – The never type
A never
type is almost always what you don't want. The compiler here could not determine the correct type at instantiation, even though we pushed string characters into the for
loop's body.
Figure 1.5 – Inferred type
Using the correct types and relying on type inference whenever possible is very important when working with TypeScript. VSCode offers good inspection utilities to do this, but a lot of times, we need to help the compiler do this.
You will learn how to work with types and understand type inference in Chapter 2, TypeScript Core Principles, in the Working with advanced types section.
Using VSCode, we can refactor the code that we are working with. Code refactoring is the process of restructuring the code base to accommodate future changes. With refactoring, we have specific end goals, such as making the code easier to read, easier to extend, or easier to navigate while keeping the same functionality.
Note
When you perform refactoring, you want to have unit tests in place before changing any existing code. This is to ensure you did not introduce any breaking changes or fail to capture edge cases.
In some cases, refactoring code can reveal potential opportunities for using design patterns, so it's a useful technique to learn. The main gotcha is that when you refactor, you need to know when to stop. Once you've applied simple refactoring, you should stop and think whether further changes to the code base are justified based on the scope of the problem you are trying to solve.
To perform simple refactoring with VSCode, you just need to highlight a specific block of code and review the options:
Chapter 1
source code folder, open the refactoring.ts
file. You will find a definition of the find
function that implements a linear search algorithm to find the elements inside a list:function find<T>(arr: T[], predicate: (item: T) => boolean) { for (let item of arr) { if (predicate(item)) { return item; } } return undefined; }
Notice that we can refactor the predicate function parameter and use it as the same type with the indexOf
function parameter. You just need to select the whole function body; that is, (item: T) => Boolean
.
Figure 1.6 – Extract to type alias option
Predicate
. This will create a type alias for this function signature:type Predicate<T> = (item: T) => boolean;
function indexOf<T>(arr: T[], predicate: Predicate<T>) { for (let i = 0; i < arr.length; i += 1) { if (predicate(arr[i])) { return i; } } return -1; }
What is the inferred return type of this function?
The answer is T
|
undefined
because we can either find the element, thus returning it, or not find it and return it undefined.
Reusing types and blocks of code like this helps you compartmentalize the code base and makes it easier to reuse.
VSCode offers additional refactoring options, such as the following:
Familiarizing yourself with these refactoring operations can help you save time and reduce typos when modifying code. In the next section, you will learn how to use Unified Modeling Language (UML) to visualize object-oriented systems.
Change the font size
Change margin width
Change background colour