TypeScript (Cheat Sheet)

This is a cheat sheet on TypeScript (mostly notes-to-self). They are incomplete by default.

Initialize a TypeScript project

yarn init -y # quickly initializes nodejs project with package.json file
yarn add typescript --dev # installs typescript
yarn tsc --init # initializes TS project with tsconfig.json file

You need to use yarn tsc --int instead of tsc --init because tsc is not installed globally. When you run yarn (or npm install), the dependencies and devDependencies from your package.json are installed locally within the node_modules folder of your project. However, the binaries from the local node_modules/.bin directory are not automatically available in your terminal environment. This is why when you try to run tsc --init directly, the terminal is unable to find the command, as it’s not installed globally.

Source: ChatGPT

Microsoft Cheat Sheets

Source: typescriptlang.org

TypeScript for Java/OOP Programmers

Source: typescriptlang.org

  • In Java:

    • everything belongs to a class or interface

    • it’s meaningful to think of a one-to-one correspondence between runtime types and their compile-time declarations

    • types are related to their declarations, not their structures.

    • the type system is (reified) nominal.

      type system  is nominal,  nominative, or name-based if compatibility and equivalence of  data types  is determined by explicit declarations and/or the name of the types. Nominal systems are used to determine if types are equivalent, as well as if a type is a subtype of another.

      Nominal type systems contrast with  structural systems , where comparisons are based on the structure of the types in question and do not require explicit declarations.

      Source: wikipedia.org

  • In TypeScript:

    • free functions (those not associated with a class) working over data without an implied OOP hierarchy are the preferred model for writing programs (in JavaScript more broadly)
    • types are sets (a particular value can belong to many sets or types at the same time)
    • classes and many common patterns such as interfaces, inheritance, and static methods are supported

For example:

// Example
interface Pointlike {
    x: number;
    y: number;
}
interface Named {
    name: string;
}

function logPoint(point: Pointlike) {
    console.log("x = " + point.x + ", y = " + point.y);
}

function logName(x: Named) {
    console.log("Hello, " + x.name);
}

const obj = {
    x: 0,
    y: 0,
    name: "Origin",
};

logPoint(obj);
logName(obj);

Source: other notes .

Non-null assertion operator (!)

Source: chatGPT

The exclamation mark (!) is known as the non-null assertion operator. It is a post-fix expression that essentially removes null and undefined from the type of the operand, allowing you to assure the TypeScript compiler that the value is non-null or non-undefined.

Background Context

In TypeScript, strict null checks can be enabled by setting the strictNullChecks flag in the tsconfig.json file. When this is enabled, variables that could be null or undefined must be checked before being used. This is done to prevent runtime errors due to null or undefined values. However, there might be cases where you, as the developer, are certain that a value would be non-null or non-undefined, even though TypeScript’s type checker cannot guarantee this. This is where the non-null assertion operator comes into play.

Step-by-Step Thinking

  1. Type Inference: TypeScript tries to infer the types of variables and object properties. When you destructure an object, TypeScript will infer the type of the variables being destructured.

    const { block } = celo.formatters; // TypeScript infers the type of block
    
  2. Nullable Types: If celo.formatters could potentially be null or undefined, TypeScript will complain that you are trying to destructure properties from a possibly null or undefined object.

    const { block } = celo.formatters; // Error if celo.formatters could be null or undefined
    
  3. Non-null Assertion: By appending ! after celo.formatters, you are telling TypeScript to treat celo.formatters as non-null or non-undefined, even if its type suggests otherwise.

    const { block } = celo.formatters!; // No error, we asserted that celo.formatters is non-null
    

Example

Here’s a TypeScript example to illustrate:

interface Celo {
    formatters?: {
        block: string;
    };
}

// Initialize with a null value for formatters
const celo: Celo = {
    formatters: null,
};

// This will result in a TypeScript error due to potential null or undefined
// const { block } = celo.formatters;

// Using ! to assert that formatters is non-null or non-undefined.
// Note: This is risky if you're not certain that formatters will always be non-null.
const { block } = celo.formatters!;

Caveats

It’s important to use the non-null assertion operator judiciously. Overusing it can lead to runtime errors if the value turns out to be null or undefined. Always ensure that you have sufficient reason to believe that the value is non-null before using the ! operator.

I hope this provides a thorough understanding of the non-null assertion operator in TypeScript.