1. Environment Setup
To work with TypeScript, you'll need Node.js installed on your system. Follow these steps:
* Install Node.js if you haven't already
* Install TypeScript globally: npm i -g typescript
* Check the version: tsc -V
* Compile manually: tsc helloworld.ts
2. Basic Data Types
| Type Name | Type |
|---|---|
| Boolean | boolean |
| Number | number |
| String | string |
| Undefined and Null | undefined/null |
| Array | number[]/Array<number> |
| Tuple | [string, number, boolean] |
| Enum | enum Color {red=1, green, blue} console.log(Color[1]) // red |
| Any and Void | any/void |
| Object | object |
| Union Type | string|number |
| Type Assertion | (<string>str)/(str as string) |
| Type Inference | let a = 100 // number type let a // any type |
| Note | Capitalized types are wrapper types, lowercase are primitive types |
3. Interfaces
a. Basic Interfaces
interface IUser {
// Read-only property
readonly username: string;
// Optional property
age?: number;
}
b. Functional Interfaces (Single Method)
interface IValidator {
(input: string): boolean;
}
c. Indexbale Interfaces
interface ICustomObject {
[propName: string]: any;
}
d. Array Interfaces
interface IStringArray {
[index: number]: string;
}
4. Classes
class Employee {
name: string;
id: number;
constructor(name: string, id: number) {
this.name = name;
this.id = id;
}
displayInfo() {
console.log(`Name: ${this.name}, ID: ${this.id}`);
}
}
5. Inheritance
interface IWorker {
performTask(task: string): boolean;
}
interface IManager extends IWorker {
assignWork(workload: number): boolean;
}
class Developer implements IManager {
department: string;
constructor(department: string) {
this.department = department;
}
performTask(task: string): boolean {
console.log(`Performing task: ${task}`);
return true;
}
assignWork(workload: number): boolean {
console.log(`Assigning workload: ${workload}`);
return true;
}
}
class SeniorDeveloper extends Developer {
constructor(department: string = 'Engineering') {
super(department);
}
reviewCode() {
super.performTask('code review');
}
}
6. Polymorphism
// Unlike Java, TypeScript doesn't support explicit type casting
let worker: IWorker = new Developer();
7. Access Modifiers
public (default): Accessible from class, subclass, and externally
private: Accessible only from within the class
protected: Accessible from the class and its subclasses
readonly: Read-only modifier (can only be modified in the constructor)
Note: Access modifiers can also be used on constructor parameters,
which automatically creates class properties from those parameters
8. Accessors (Gettters and Setters)
// If only getter is defined, property is read-only
// If only setter is defined, property is write-only
// If both or neither are defined, property is read-write
class Product {
private _price: number;
get price(): number {
return this._price;
}
set price(value: number) {
if (value >= 0) {
this._price = value;
} else {
throw new Error('Price cannot be negative');
}
}
}
9. Static Members
// Unlike Java, instance objects cannot access static members
class Calculator {
// Note: name is a built-in property, so it cannot be used as a static member
static PI: number = 3.14159;
static calculateCircumference(radius: number): number {
return 2 * Calculator.PI * radius;
}
}
10. Abstract Classes
abstract class Vehicle {
abstract brand: string;
abstract move(): void;
}
class Car extends Vehicle {
// Unlike Java, abstract properties must be explicitly implemented
brand: string;
constructor(brand: string) {
super();
this.brand = brand;
}
move(): void {
console.log(`${this.brand} car is moving`);
}
}
11. Functions
// Method 1
function add(a: number, b: number): number {
return a + b;
}
// Method 2
const subtract: (x: number, y: number) => number = function(x: number, y: number): number {
return x - y;
}
12. Parameters
a. Default Parameters
function greet(name: string = 'Guest'): void {
console.log(`Hello, ${name}!`);
}
b. Optional Parameters
function buildName(firstName: string, lastName?: string): void {
if (lastName) {
console.log(`${firstName} ${lastName}`);
} else {
console.log(`${firstName}`);
}
}
c. Rest Parameters
// Rest parameters must be the last parameter in the list
function sum(...numbers: number[]): number {
return numbers.reduce((total, current) => total + current, 0);
}
13. Function Overloading
function combine(a: string, b: string): string;
function combine(a: number, b: number): number;
function combine(a: any, b: any): any {
return a + b;
}
14. Generics
a. Generic Functions
function createPair<K, V>(key: K, value: V): [K, V] {
return [key, value];
}
b. Generic Interfaces
interface Collection<T> {
add(item: T): void;
get(index: number): T;
}
c. Generic Classes
class Box<T> {
private content: T;
constructor(value: T) {
this.content = value;
}
getValue(): T {
return this.content;
}
}
d. Generic Constraints
interface Lengthy {
length: number;
}
function getLength<T extends Lengthy>(arg: T): number {
return arg.length;
}
15. Declaration Files
/*
When using third-party libraries, we need to reference their declaration files
to get code completion, interface hints, and other features.
Declaration statement: If TypeScript needs to check new syntax,
the corresponding type description code must be loaded.
declare var jQuery: (selector: string) => any;
Declaration file: Put declaration statements in a separate file (jquery.d.ts),
TypeScript will automatically parse all declaration files in the project.
Download declaration files: npm install @types/jquery --save-dev
*/
import jQuery from "jquery";
jQuery('selector');
16. Built-in Objects
a. ECMAScript Built-in Objects
Boolean
Number
String
Date
RegExp
Error
b. BOM and DOM Built-in Objects
Window
Document
HTMLElement
DocumentFragment
Event
NodeList
c. TypeScript Extended Classes
Canvas element object: HTMLCanvasElement
Form element object: HTMLFormElement
17. Type Aliases
a. Custom Type Aliases
type ID = string | number;
b. String Literal Types
type Gender = 'Male' | 'Female' | 'Other';
18. Namespaces
// ES2015 module syntax is preferred over custom TypeScript modules and namespaces
export namespace com {
export namespace example {
export namespace models {
export class User {
username: string;
constructor(username: string) {
this.username = username;
}
}
}
}
}
19. Decorators
a. Simple Decorators (No Parameters)
// Define a decorator
function logClass(constructor: Function) {
// The constructor parameter is the class being decorated
constructor.prototype.createdDate = new Date();
constructor.prototype.getInfo = function() {
return `Class created on ${this.createdDate}`;
}
}
@logClass
class Repository {
save() {
console.log('Saving data');
}
}
function logClass(constructor: any) {
// This will override properties and methods of the decorated class
return class extends constructor {
version = '1.0.0';
constructor(...args: any[]) {
super(...args);
}
save() {
console.log('Logging before save');
super.save();
}
}
}
@logClass
class Repository {
version = '0.0.1';
save() {
console.log('Saving data');
}
}
b. Decorator Factories (With Parameters)
// Define a decorator factory
function logClassWithParams(logLevel: string) {
return function(target: Function) {
console.log(`Log level: ${logLevel}`);
// The target parameter is the class being decorated
console.log(target);
}
}
@logClassWithParams('debug')
class Repository {
save() {
console.log('Saving data');
}
}
c. Property Decorators
function logProperty(value: any) {
// When decorating a static property, target is the constructor function
// When decorating an instance property, target is the prototype object
return function(target: any, propertyKey: string) {
console.log(target);
console.log(propertyKey);
target[propertyKey] = value;
}
}
class Repository {
@logProperty('default')
static connectionString: string = 'default';
@logProperty('instance')
tableName: string = 'table';
}
d. Method Decorators
function logMethod(value: any) {
// When decorating a static method, target is the constructor function
// When decorating an instance method, target is the prototype object
// methodName: name of the method
// descriptor: method descriptor information
return function(target: any, methodName: string, descriptor: PropertyDescriptor) {
console.log(value);
console.log(target);
console.log(methodName);
console.log(descriptor);
// descriptor.value is the function object of the decorated method
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Method ${methodName} called with args:`, args);
return originalMethod.apply(this, args);
}
}
}
class Repository {
@logMethod('debug')
save(data: any) {
console.log('Saving data:', data);
}
}
e. Parameter Decorators
function logParameter(value: any) {
// When decorating a static method parameter, target is the constructor function
// When decorating an instance method parameter, target is the prototype object
// methodName: name of the method
// parameterIndex: index of the parameter
return function(target: any, methodName: string, parameterIndex: number) {
console.log(value);
console.log(target);
console.log(methodName);
console.log(parameterIndex);
}
}
class Repository {
save(@logParameter('data') data: any) {
console.log('Saving data:', data);
}
}
f. Decorator Execution Order
* Property decorators -> Method decorators -> Parameter decorators -> Class decorators
* If there are multiple decorators of the same type, they are executed from bottom to top