ajhsu / blog

The external storage of my brain.
3 stars 0 forks source link

TypeScript #99

Open ajhsu opened 2 years ago

ajhsu commented 2 years ago

Core features

Terminologies

Downleveling

Type annotations

let person: string = 'Alice';
//          ^^^ type annotations

// We can either use , or ; to separate properties for object type,
// and the last separator is optional.
function printCoord(pt: { x: number, y: number }) {}
function printCoord(pt: { x: number; y: number }) {}

Inference

Contextual typing

The static checker can infer the type of the elements within an array.

// No type annotations here, but TypeScript can spot the bug
const names = ["Alice", "Bob", "Eve"];

// Contextual typing for function
names.forEach(function (s) {
  console.log(s.toUppercase());
Property 'toUppercase' does not exist on type 'string'. Did you mean 'toUpperCase'?
});

Union types

function printId(id: number | string) {}
//                   ^^^ union type, where `number` and `string` are union's members

Narrowing

Narrowing occurs when TypeScript can deduce a more specific type for a value based on the structure of the code.

// Narrowing example 1
function printId(id: number | string) {
  console.log(id.toUpperCase());
  // Error: Property 'toUpperCase' does not exist on type 'string | number'.
  // Error: Property 'toUpperCase' does not exist on type 'number'.
}

function printId(id: number | string) {
  if (typeof id === "string") {
    // In this branch, id is of type 'string'
    console.log(id.toUpperCase());
  } else {
    // Here, id is of type 'number'
    console.log(id);
  }
}
// Narrowing example 2
function welcomePeople(x: string[] | string) {
  if (Array.isArray(x)) {
    // Here: 'x' is 'string[]'
    console.log("Hello, " + x.join(" and "));
  } else {
    // Here: 'x' is 'string'
    console.log("Welcome lone traveler " + x);
  }
}

Type alias

type Point = {
  x: number;
  y: number;
};

// Exactly the same as the earlier example
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}

// Or use like this
type ID = number | string;

function sanitizeInput(str: string): UserInputSanitizedString { return sanitize(str); }

// Create a sanitized input let userInput = sanitizeInput(getInput());

// Can still be re-assigned with a string though userInput = "new input";


### ***Interface***
```ts
interface Point {
  x: number;
  y: number;
}

function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}

Difference between type alias and interface

  1. The key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable. See this doc for more details.

Type Assertion

You can use a type assertion to specify a more specific type:

const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;

You can also use the angle-bracket syntax (except if the code is in a .tsx file), which is equivalent:

const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

Reminder: Because type assertions are removed at compile-time, there is no runtime checking associated with a type assertion. There won’t be an exception or null generated if the type assertion is wrong.

TypeScript only allows type assertions which convert to a more specific or less specific version of a type. But not conversion that is impossible (e.g., assert a string is number)

Sometimes this rule can be too conservative and will disallow more complex coercions that might be valid. If this happens, you can use two assertions, first to any (or unknown), then to the desired type:

const a = (expr as any) as T;

Literal Types

var alignment: "left" | "right" | "center" = "center";

function compare(a, b): -1 | 0 | 1 {}

function configure(opts: Options | "auto") {}

Non-null Assertion Operator

// Assert that the foo won't be null
foo!.toUpperCase();

Practices

Common pitfalls

Migrate from JavaScript

ajhsu commented 2 years ago

Terminologies

// "type guard"
if (typeof padding === "number") {}

// to "guard against" values like null or undefined
if (foo && foo === "hello") {}