Skip to content

Instantly share code, notes, and snippets.

@subrotoice
Last active April 16, 2025 02:50
Show Gist options
  • Select an option

  • Save subrotoice/e7e902e86dece9606090c3613a23e6e5 to your computer and use it in GitHub Desktop.

Select an option

Save subrotoice/e7e902e86dece9606090c3613a23e6e5 to your computer and use it in GitHub Desktop.

TypeScript 101

TypeScript: JavaScript with Type Checking

  • Error checking at compile time. So less testing like unit test
  • Type checking, Code Completion, Refactoring, New features

Transpilation: .ts --> Com;iler --> .js

Install Typescript

npm i -g typescript
tsc -v // Version 5.8.3

First typescript program

let num1: number = 20;
tsc index.ts

This command create index.js

var num1 = 20;

Create typescript configaration file

tsc --init

See some options. If we remove es2016 and press ctrl+space we can see all options

"target": "es2016",
"module": "commonjs",
"rootDir": "./", // "rootDir": "./src",
"outDir": "./dist",
"removeComments": true,
"noEmitOnError": true,

Now if we run "tsc" in terminal, typescript compiler will complile all file in this project.

Ch1: Basic types

Explicit - writing out the type

let firstName: string = "Dylan";

Explicit type assignment are easier to read and more intentional. Note: Having TypeScript "guess" the type of a value is called infer.

  • Error
let firstName: string = "Dylan"; // type string
firstName = 33; // attempts to re-assign the value to a different type

Implicit type assignment

Throw error

let firstName = "Dylan"; // inferred to type string
firstName = 33; // attempts to re-assign the value to a different type

Special Types

Special Types

  1. Type: any

  2. Type: unknown

  3. any Purpose: Opt-out of type checking

Behavior:

Allows assignment of any value Allows access to any property/method without type checking Essentially turns off TypeScript's type system for the variable

let anything: any = "hello";
anything = 42; // OK
anything = true; // OK
anything.nonExistentMethod(); // No error (runtime error possible)
  1. unknown Purpose: Type-safe counterpart of any

Behavior:

  • Can hold any value (like any)
  • Cannot be used directly without type checking or type assertion
  • Forces you to validate the type before using it
let uncertain: unknown = "hello";

// These would cause errors:
// uncertain.toUpperCase();
// let str: string = uncertain;

// Proper usage:
if (typeof uncertain === "string") {
  uncertain.toUpperCase(); // OK
}

// Or with type assertion:
(uncertain as string).toUpperCase();

Arrays

const names: string[] = [];
names.push("Subroto"); // no error
// names.push(3); // Error: Argument of type 'number' is not assignable to parameter of type 'string'.

TypeScript can infer the type of an array if it has values.

const numbers = [1, 2, 3]; // inferred to type number[]
numbers.push(4); // no error
// comment line below out to see the successful assignment
numbers.push("2"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
let head: number = numbers[0]; // no error

Tuples: Typed Arrays

// define our tuple
let ourTuple: [number, boolean, string];

// initialize correctly
ourTuple = [5, false, "Coding God was here"];

Object Types

TypeScript has a specific syntax for typing objects.

const car: { type: string, model: string, year: number } = {
  type: "Toyota",
  model: "Corolla",
  year: 2009,
};

Object types like this can also be written separately, and even be reused, achiving by interfaces.

Type Aliases and Interfaces

TypeScript allows types to be defined separately from the variables that use them. Aliases and Interfaces allows types to be easily shared between different variables/objects.

Type Aliases

Type Aliases allow defining types with a custom name (an Alias).

Type Aliases can be used for primitives like string or more complex types such as objects and arrays:

type CarYear = number;
type CarType = string;
type CarModel = string;
type Car = {
  year: CarYear,
  type: CarType,
  model: CarModel,
};

const carYear: CarYear = 2001;
const carType: CarType = "Toyota";
const carModel: CarModel = "Corolla";
const car: Car = {
  year: carYear,
  type: carType,
  model: carModel,
};

Interfaces

Interfaces are similar to type aliases, except they only apply to object types.

interface Rectangle {
  height: number;
  width: number;
}

const rectangle: Rectangle = {
  height: 20,
  width: 10,
};

Extending Interfaces

interface Rectangle {
  height: number;
  width: number;
}

interface ColoredRectangle extends Rectangle {
  color: string;
}

const coloredRectangle: ColoredRectangle = {
  height: 20,
  width: 10,
  color: "red",
};

Functions

TypeScript has a specific syntax for typing function parameters and return values.

Return Type

The : number here specifies that this function returns a number

function getTime(): number {
  return new Date().getTime();
}

If no return type is defined, TypeScript will attempt to infer it through the types of the variables or expressions returned.

Void Return Type

The type void can be used to indicate a function doesn't return any value.

function printHello(): void {
  console.log("Hello!");
}

Parameters

Function parameters are typed with a similar syntax as variable declarations.

function multiply(a: number, b: number) {
  return a * b;
}

If no parameter type is defined, TypeScript will default to using any, unless additional type information is available as in the Default Parameters.

Optional Parameters

By default TypeScript will assume all parameters are required, but they can be explicitly marked as optional.

The ? operator here marks parameter c as optional

function add(a: number, b: number, c?: number) {
  return a + b + (c || 0);
}

Default Parameters

For parameters with default values, the default value goes after the type annotation:

function pow(value: number, exponent: number = 10) {
  return value ** exponent;
}

Named Parameters

Typing named parameters follows the same pattern as typing normal parameters.

function divide({ dividend, divisor }: { dividend: number, divisor: number }) {
  return dividend / divisor;
}

Rest Parameters

Rest parameters can be typed like normal parameters, but the type must be an array as rest parameters are always arrays.

function add(a: number, b: number, ...rest: number[]) {
  return a + b + rest.reduce((p, c) => p + c, 0);
}

Casting

Casting with as A straightforward way to cast a variable is using the as keyword, which will directly change the type of the given variable.

let x: unknown = 'hello';
console.log((x as string).length);

Casting doesn't actually change the type of the data within the variable, for example the following code will not work as expected since the variable x is still holds a number.

let x: unknown = 4;
console.log((x as string).length); // prints undefined since numbers don't have a length

Generics: type variables

Generics makes it easier to write reusable code.

Functions

Generics with functions help make more generalized methods which more accurately represent the types used and returned.

function createPair<S, T>(v1: S, v2: T): [S, T] {
  return [v1, v2];
}
console.log(createPair < string, number > ("hello", 42)); // ['hello', 42]

Classes

Generics can be used to create generalized classes, like Map.

class NamedValue<T> {
  private _value: T | undefined;

  constructor(private name: string) {}

  public setValue(value: T) {
    this._value = value;
  }

  public getValue(): T | undefined {
    return this._value;
  }

  public toString(): string {
    return `${this.name}: ${this._value}`;
  }
}

let value = new NamedValue<number>('myNumber');
value.setValue(10);
console.log(value.toString()); // myNumber: 10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment