Reader small image

You're reading from  TypeScript 4 Design Patterns and Best Practices

Product typeBook
Published inSep 2021
Reading LevelIntermediate
PublisherPackt
ISBN-139781800563421
Edition1st Edition
Right arrow
Author (1)
 Theofanis Despoudis
Theofanis Despoudis
author image
Theofanis Despoudis

Theo Despoudis lives in Ireland, where he works as a Software Engineer for WP Engine and as a part-time tech practitioner for Fixate. He is the co-author of The React Workshop and Advanced Go Programming in 7 Days, Dzone Core Member, and maintains some open source projects on GitHub. Theo is available for conference talks, independent consulting, and corporate training services opportunities.
Read more about Theofanis Despoudis

Right arrow

Introducing TypeScript 4

Understanding the basic language constructs of TypeScript is very valuable when learning design patterns. You will need to recognize valid TypeScript code and some of its features because it will help you define better typings for objects, as well as help you avoid mistakes. We will strive to provide small but consistent examples and use cases of TypeScript idioms and constructs for completeness.

The basic structure of a TypeScript program consists of statements or expressions. The following is a list of basic types that are partly associated with JavaScript runtime types:

  • Primitive types: These are number, string, Boolean, void, null, undefined, unknown, never, unique, bigint, and any values. To define or declare them, you need to write the name of the variable, followed by a semicolon (:) and its type. If you assign the wrong type, then the compiler will throw an error. Here is an example usage of those types (intro.ts):
    const one: string = "one";
    const two: boolean = false;
    const three: number = 3;
    const four: null = null;
    const five: unknown = 5;
    const six: any = 6;
    const seven: unique symbol = Symbol("seven");
    let eight: never; // note that const eight: never cannot happen as we cannot instantiate a never
  • Enums: They allow us to create named constants, such as the following:
    enum Keys {
      Up,
      Down,
      Left,
      Right,
    }
    let up: Keys = Keys.Up;

    You can enforce a compiler optimization with enums to make them constant, thus eliminating any unused information:

    const enum Bool {
      True,
      False,
    }
     
    let truth: Bool = Bool.True;
  • Array and tuples: Arrays represent a collection of items of the same type, and they can have a variable size:
    const arr: number[] = [1, 2, 3]; // array of numbers of any size

    Tuples represent a fixed array, with each element having a defined type:

    const tup: [number] = [1]; // tuple with one element of type number
  • Classes: These are typical Object-Oriented Programming (OOP) abstractions that allow us to define objects of a specific shape with properties, methods, and visibility modifiers. For example, here is a typical use case of a class:
    class User {
      private name: string;
      constructor(name: string) {
        this.name = name;
      }
     
      public getName(): string {
        return this.name;
      }
    }
     
    const user = new User("Theo");
    console.log(user.getName()); // prints "Theo"

    You can also define abstract classes (that is, regular classes) that cannot be instantiated. Instead, they need to be inherited as part of a parent-child relationship:

    abstract class BaseApiClient {
      abstract fetch(req: any): Promise<any>; /* must be implemented in sub-classes*/
    }
    class UsersClient extends BaseApiClient {
      fetch(req: any): Promise<any> {
        return Promise.resolve([]);
      }
    }
    const client = new UsersClient();
    client.fetch({url: '/users'});
  • Interfaces and types: Interfaces are abstractions that let you define the shape of an object and its properties, but without specifying an implementation. For example, we can define a Comparable interface like this:
    interface Comparable<T> {
        compareTo(o: T): number
    }

    Note that we are not defining an implementation for compareTo here, just its type. Interfaces in TypeScript can also have properties:

    interface AppConfig {
        paths: {
            base: string;
        };
        maxRetryCount?: number;
    }

    The question mark (?) after the name represents an optional parameter, so it's allowed to create a type with or without it:

    const appConfig: AppConfig = {
        paths: {
            base: '/',
        }
    }

    Type is a similar concept to interfaces but is a bit more flexible. You can combine a Type with another Type either as a union or as an intersection type:

    type A = 'A'; // type is 'A'
    type B = 'B'; // type is 'B'
     
    type C = A & B; /* type is never as there is nothing in common between A and C*/
    type D = C | "E"; // type is "E" as C is a never type
    type E = {
        name: string;
    }
    type F = E & {
        age: number;
    }
    let e: F = {
        name: "Theo",
        age: 20
    }

    Note

    As a rule of thumb, you should be declaring interfaces first. However, when you want to combine or create new types on the fly, then you should use types.

There are many other notable features of TypeScript that you will learn about throughout this book. Now, let's move on and learn how to handle input and output.

Working with input and output

Understanding how to read from input and write to output is one of the most fundamental skills of any programming language. Handling input and output operations with TypeScript depends primarily on where you use it. For example, when using TypeScript in a browser environment, you accept input from user interactions, such as when a user clicks on a button and submits a form or when you send an AJAX request to a server.

When using TypeScript in a server, you can read input values from command-line arguments or from the standard input stream (stdin). Subsequently, we can write values to the output stream, called the standard output stream (stdout). All these concepts are common to all computer environments.

As an example, let's take a case where we are using TypeScript with Node.js. We can use the following simple program to read from stdin and write to stdout:

inputOutput.ts

const stream = process.stdin;
setImmediate(function () {
  stream.push(null);
});
 
stream.pipe(process.stdout);

Then, you can invoke this program from the command line:

 echo "Hello" | npm run ts chapters/chapter-1_Getting_Started_With_Typescript_4/inputOutput.ts
Hello World

Working with streams exposes a different programming model, called reactive programming, where you are concerned about asynchronous data streams and events. You will learn more about asynchronous communication patterns in Chapter 7, Reactive Programming with TypeScript.

Useful TypeScript 4 features

The latest version of TypeScript (v4.2) offers a great list of features that help developers write type-safe programs and abstractions. For example, with TypeScript 4, we have the following:

  • Variadic tuple types: Tuples are interesting data structures as they represent fixed array types, where each element has a specific type. For example, we can model a point in 2D or 3D space as a tuple:
    type Point2d = [number, number];
    type Point3d = [number, number, number];
    const point1: Point2d = [1, 2];
    const point2: Point3d = [1, 2, 3];

    Before TypeScript 4, you could not pass a variadic type parameter for a tuple as the shape of the tuple had to be defined. Now, let's check out the following code:

    type NamedType<T extends unknown[]> = [string, ...T];
    type NamedPoint2d = NamedType<Point2d>;
    const point3: NamedPoint2d = ["Point: (1, 2)", 1, 2];

    Here, the type of NamedPoint2d is [string, number, number]. With this feature, we may have more compelling reasons to use tuples to model domain primitives.

  • Labeled tuples: Taking the previous example with the two tuples, we can also add names for each tuple element. This can improve documentation as you can clearly see the corresponding parameter for each item. For example, let's add labels to show the usage of x, y, and z coordinates:
    type Point2dL = [x: number, y: number];
    type Point3dL = [x: number, y: number, z: number]; 

    Labeled tuples are useful for documentation purposes; so, if you use tuples, you should also provide labels for them.

  • Template literal types: TypeScript 4 has added a new literal type for templates that allows us to combine types. This helps when defining new types out of existing ones and you want to avoid repetition. For example, we can model a Deck of Cards type using just two lines of code:
    type Suit = `${"Spade" | "Heart" | "Diamond" | "Club"}`;
    type Rank = `${"2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "Jack" | "Queen" | "King" | "Ace"}`
     
    type Deck = `${Rank} of ${Suit}`;

If you inspect the type of the Deck declaration, you will see that it enumerates the possible cards of a standard 53 deck of cards: 2 of Spade, 3 of Spade …, Ace of Club.

Now that we've introduced and understood TypeScript 4's features, let's learn how TypeScript and JavaScript are related to each other.

Previous PageNext Page
You have been reading a chapter from
TypeScript 4 Design Patterns and Best Practices
Published in: Sep 2021Publisher: PacktISBN-13: 9781800563421
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Theofanis Despoudis

Theo Despoudis lives in Ireland, where he works as a Software Engineer for WP Engine and as a part-time tech practitioner for Fixate. He is the co-author of The React Workshop and Advanced Go Programming in 7 Days, Dzone Core Member, and maintains some open source projects on GitHub. Theo is available for conference talks, independent consulting, and corporate training services opportunities.
Read more about Theofanis Despoudis