TypeScript
TypeScript is JavaScript with added syntax for types.
- TypeScript being converted into JavaScript means it runs anywhere that JavaScript runs!
- Add to project with npm:
npm install typescript --save-dev
- Check:
npx tsc
- Config compiler:
npx tsc --init
->tsconfig.json
Basic Types
// Type Assignment
let firstName: string = 'Dylan'; // Explicit
let firstName = 'Dylan'; // Implicit -> auto be string
// Primitives type
let isTrue: boolean = false;
let firstNum: number = 0;
let yourName: string = 'My Name';
let myVirtualBalance = new BigInt('999999999999999');
let mySymbol: symbol = new Symbol('SIMP');
// SPECIAL
// 'undefined' | 'null' maybe useless
let dontUseThis: never;
let thing: any;
let something: unknown; // any but safe, cast with "as"
// () => void -> function return undefined
function doIt(): () => void { }
// T[]
const listAgeValid: number[] = [];
const BLACK_LIST: readonly string[] = [];
// Tuples: [T1, T2, ..., Tn]
// - Can use 'readonly'
const materials: [string, number, boolean] = ['truffles', 2, false];
// Object
let car : {
model: string,
year: number,
mileage?: number, // OPTIONAL property
[x: string]: any, // OPTIONAL information
}
Enums
enum CardinalDirections {
North, // 1
East,
South,
West // 4
}
enum StatusCodes {
NotFound = 404, // it can be string like "404"
Success = 200,
Accepted = 202,
BadRequest = 400
}
// Exp: StatusCode.NotFound
Interfaces & Type Aliases
interface
interface
only apply to objectinterface
canextend
each other's definition.
interface Rectangle {
height: number,
width: number
}
const rectangle: Rectangle = {
height: 20,
width: 10
};
interface ColoredRectangle extends Rectangle {
color: string
}
// keyof ColoredRectangle -> 'height' | 'width' | 'color'
// variable: keyof Interface (or ObjectType)
const coloredRectangle: ColoredRectangle = {
height: 20,
width: 10,
color: "red"
};
type aliases
info
- Recommend using
type
instead ofinterface
if not useclass
- Interface vs Type
type CarYear = number | string; // Union types - value can be 1 of 2 types
type CarType = string;
type CarModel = string;
type Car = {
year: CarYear,
type: CarType,
model: CarModel
}
const carYear: CarYear = 2001; // or "2001"
const carType: CarType = "Toyota"
const carModel: CarModel = "Corolla"
const car: Car = {
year: carYear,
type: carType,
model: carModel
};
// Type Alias
type Negate = (value: number) => number;
// in this function, the parameter `value` automatically gets assigned
// the type `number` from the type `Negate`
const negateFunction: Negate = (value) => value * -1;
Casting
// var as type
let value = x as string;
// <type>var
let value = <string>x;
// Force casting - Usually use for fetching data
let value = (x as unknown) as number;
Class
- Review: JavaScript Class
- JavaScript Class with clear OOP
- Visibility modifiers
private
- Class member onlyprotected
- Class member, Classes inherit itpublic
- anywhere
implements
multipleinterface
extends
only oneclass
override
functionabstract
class - not use to create Object
class Person {
private name: string;
// private readonly name: string; // now name can't change
// Use private with params
// public constructor(private name: string) {}
public constructor(name: string) {
this.name = name;
}
public getName(): string {
return this.name;
}
}
const person = new Person("Jane");
// person.name isn't accessible from outside the class since it's private
console.log(person.getName());
interface Shape {
getArea: () => number;
}
class Rectangle implements Shape {
// using protected for these members allows access
// from classes that extend from this class, such as Square
public constructor(
protected readonly width: number,
protected readonly height: number
) {}
public getArea(): number {
return this.width * this.height;
}
public toString(): string {
return `Rectangle[width=${this.width}, height=${this.height}]`;
}
}
class Square extends Rectangle {
public constructor(width: number) {
super(width, width);
}
// this toString replaces the toString from Rectangle
public override toString(): string {
return `Square[width=${this.width}]`;
}
}
abstract class Polygon {
public abstract getArea(): number;
public toString(): string {
return `Polygon[area=${this.getArea()}]`;
}
}
class Rectangle extends Polygon {
public constructor(
protected readonly width: number,
protected readonly height: number
) {
super();
}
public getArea(): number {
return this.width * this.height;
}
}
Generic
// string is default type if it not provide
class NamedValue<T = string> {
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}`;
}
}
const value = new NamedValue('myNumber');
value.setValue('myValue');
console.log(value.toString()); // myNumber: myValue
const value2 = new NamedValue<number>('myNumber');
value2.setValue(10);
console.log(value2.toString()); // myNumber: 10
interface Nested<T> {
something: T
}
type Wrapped<T> = { value: T };
const wrappedValue: Wrapped<number> = { value: 10 };
// extends limit types
function createLoggedPair<S extends string | number, T extends string | number>(v1: S, v2: T): [S, T] {
console.log(`creating pair: v1='${v1}', v2='${v2}'`);
return [v1, v2];
}
console.log(createPair<string, number>('hello', 42)); // ['hello', 42]
Utility Types
Record<K, V>
Excludes<TypeUnion, TypeRemove>
Readonly<T>
- Apply TS features onlyPatial<I>
- All keys are OPTIONALRequired<I>
- All keys are REQUIREDOmit<I, 'key1' | 'key2'>
- Remove keys of interfacePick<I, 'key1' | 'key2'>
- Choose keys of interface- function
ReturnType<FT>
Parameters<FT>[paramIndex]
const nameAgeMap: Record<string, number> = { 'Alice': 21, 'Bob': 25 };
interface Car {
make: string;
model: string;
mileage?: number;
}
const nothingCar: Partial<Car> = {};
const myCar: Required<Car> = {
make: 'Ford',
model: 'Focus',
mileage: 12000 // `Required` forces mileage to be defined
};
type Primitive = string | number | boolean
const value: Exclude<Primitive, string> = "Hello"; // Error
type PointGenerator = () => { x: number; y: number; };
// { x: number, y: number }
const point: ReturnType<PointGenerator> = { x: 10, y: 20 };
type PointPrinter = (p: { x: number; y: number; }, ss?: boolean) => void;
// 0: { x: number, y: number }
// 1: boolean
// 2: undefined
const point: Parameters<PointPrinter>[0] = { x: 10, y: 20 };
TypeScript 5.x+
Template Literal Types
type Color = "red" | "green" | "blue";
type HexColor<T extends Color> = `#${string}`;
// Usage:
let myColor: HexColor<"blue"> = "#0000FF";
Index Signature Labels
type DynamicObject = { [key: string as `dynamic_${string}`]: string };
// Usage:
let obj: DynamicObject = { dynamic_key: "value" };