INNER PEACE

Learn Typescript in One File

Attempting to Fit All TypeScript Features in One File (Updated with AI in 2024-8)

TypeScript is a superset of JavaScript that introduces a type system on top of the original, making code more maintainable. I haven’t written much serious TypeScript yet, but while learning, it’s clear that TypeScript would be easier to maintain in larger projects compared to not having a type system (though I haven’t verified this in a project yet). I hope to introduce it in my future code as well.

Here, I want to try to illustrate all of its concepts as much as possible by creating a class.

// Demonstrates interfaces, generics, and union types
interface Printable<T> {
  print(): T | string;
}

// Enum declaration
enum Color {
  Red,
  Green,
  Blue
}

// Type alias
type NumberOrString = number | string;

// Class declaration with generics, implementing an interface
class TypeScriptShowcase<T> implements Printable<T> {
  // Private field
  private data: T;

  // Public readonly property
  public readonly id: NumberOrString;

  // Constructor with parameter properties
  constructor(public name: string, private age: number = 30) {
    this.id = Date.now();
  }

  // Getter
  get info(): string {
    return `${this.name} (${this.age})`;
  }

  // Setter
  set info(value: string) {
    [this.name, this.age] = value.split(' ');
    this.age = Number(this.age);
  }

  // Method with rest parameters and arrow function
  public greet = (...names: string[]): void => {
    console.log(`Hello, ${names.join(', ')}!`);
  }

  // Static method
  static createInstance<U>(data: U): TypeScriptShowcase<U> {
    return new TypeScriptShowcase<U>("Default", 25);
  }

  // Implementation of interface method
  print(): T | string {
    return `Data: ${this.data}`;
  }

  // Method with function overloading
  public process(input: number): number;
  public process(input: string): string;
  public process(input: number | string): number | string {
    return typeof input === 'number' ? input * 2 : input.toUpperCase();
  }

  // Async method
  public async fetchData(): Promise<T> {
    // Simulating an API call
    return new Promise(resolve => setTimeout(() => resolve(this.data), 1000));
  }

  // Method using a tuple type
  public swapValues(a: T, b: T): [T, T] {
    return [b, a];
  }
}

// Usage of the class
const showcase = new TypeScriptShowcase<string>("Alice", 25);
showcase.greet("Bob", "Charlie");
console.log(showcase.info);
showcase.info = "David 35";
console.log(showcase.process(10));
console.log(showcase.process("hello"));

// Decorators (experimental feature)
function logged(target: any, key: string, descriptor: PropertyDescriptor) {
  const original = descriptor.value;
  descriptor.value = function(...args: any[]) {
    console.log(`Calling ${key} with`, args);
    return original.apply(this, args);
  };
  return descriptor;
}

class DecoratorExample {
  @logged
  multiply(a: number, b: number): number {
    return a * b;
  }
}

const dec = new DecoratorExample();
dec.multiply(2, 3);

// Demonstrating keyof and mapped types
type Keys = keyof TypeScriptShowcase<any>;
type ReadonlyTypeScriptShowcase<T> = {
  readonly [P in keyof TypeScriptShowcase<T>]: TypeScriptShowcase<T>[P];
};

// Conditional types
type NonNullable<T> = T extends null | undefined ? never : T;

// Utility types
type Partial<T> = {
  [P in keyof T]?: T[P];
};

type Required<T> = {
  [P in keyof T]-?: T[P];
};

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

type Record<K extends keyof any, T> = {
  [P in K]: T;
};

// Using a namespace
namespace Validation {
  export interface StringValidator {
    isAcceptable(s: string): boolean;
  }

  const lettersRegexp = /^[A-Za-z]+$/;
  const numberRegexp = /^[0-9]+$/;

  export class LettersOnlyValidator implements StringValidator {
    isAcceptable(s: string) {
      return lettersRegexp.test(s);
    }
  }

  export class ZipCodeValidator implements StringValidator {
    isAcceptable(s: string) {
      return s.length === 5 && numberRegexp.test(s);
    }
  }
}

// Using the namespace
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();