skills/knoopx/pi/typescript

typescript

SKILL.md

TypeScript

Type-safe JavaScript with static typing and modern features.

Quick Start

bun init --typescript    # Initialize project
bunx tsc --noEmit        # Type check
vitest run               # Run tests

Configuration

tsconfig.json

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "lib": ["ESNext"],
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

Strict Mode Options

Option Description
strictNullChecks Enforce strict null checks
strictFunctionTypes Strict function parameter types
noImplicitAny Disallow implicit any types
alwaysStrict Apply all strict checks

Type Definitions

Basic Types

let str: string = "hello";
let num: number = 42;
let bool: boolean = true;
let arr: number[] = [1, 2, 3];
let tuple: [string, number] = ["age", 25];
let obj: { name: string; age: number } = { name: "John", age: 30 };

Interfaces vs Types

// Interface for object shapes
interface User {
  id: number;
  name: string;
  email: string;
}

// Type for unions and function signatures
type Status = "loading" | "success" | "error";
type CreateUser = (data: Partial<User>) => Promise<User>;

// Discriminated union
type Result<T> = { ok: true; value: T } | { ok: false; error: Error };

Utility Types

type PartialUser = Partial<User>;
type RequiredUser = Required<User>;
type ReadonlyUser = Readonly<User>;
type UserName = Pick<User, "name">;
type UserWithoutEmail = Omit<User, "email">;

Functions

// Basic function
function add(a: number, b: number): number {
  return a + b;
}

// Arrow function
const add = (a: number, b: number): number => a + b;

// Optional parameters
function greet(name: string, title?: string): string {
  return title ? `${title} ${name}` : name;
}

// Rest parameters
function sum(...nums: number[]): number {
  return nums.reduce((a, b) => a + b, 0);
}

// Function overloads
function format(input: string): string;
function format(input: number): string;
function format(input: string | number): string {
  return String(input);
}

// Async function
async function fetchData(url: string): Promise<unknown> {
  const response = await fetch(url);
  return response.json();
}

Classes

class Person {
  constructor(
    public name: string,
    private age: number,
  ) {}

  greet(): string {
    return `Hello, ${this.name}`;
  }
}

// Inheritance
class Employee extends Person {
  constructor(
    name: string,
    age: number,
    public role: string,
  ) {
    super(name, age);
  }
}

// Abstract class
abstract class Shape {
  abstract area(): number;
}

Generics

// Generic function
function wrap<T>(value: T): { value: T } {
  return { value };
}

// Generic class
class Container<T> {
  constructor(private value: T) {}
  get(): T {
    return this.value;
  }
}

// Generic constraints
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

Type Guards

function isString(value: unknown): value is string {
  return typeof value === "string";
}

function isUser(value: unknown): value is User {
  return (
    typeof value === "object" &&
    value !== null &&
    "id" in value &&
    "name" in value
  );
}

function process(value: unknown) {
  if (isString(value)) {
    console.log(value.toUpperCase()); // value is string
  }
}

Error Handling

Custom Errors

class ValidationError extends Error {
  constructor(
    public field: string,
    message: string,
  ) {
    super(message);
    this.name = "ValidationError";
  }
}

Result Type

type Result<T, E = Error> = { ok: true; value: T } | { ok: false; error: E };

function safeParse(json: string): Result<unknown> {
  try {
    return { ok: true, value: JSON.parse(json) };
  } catch (error) {
    return { ok: false, error: error as Error };
  }
}

Compilation

tsc                    # Compile
tsc --noEmit           # Type check only
tsc --watch            # Watch mode (use tmux)

tmux new -d -s tsc 'tsc --watch'

Best Practices

  • Use strict: true in tsconfig
  • Avoid any - use unknown or specific types
  • Prefer interfaces for object shapes
  • Use branded types for primitives needing validation
  • Make invalid states unrepresentable
  • Type at boundaries (API inputs/outputs)

Tips

  • tsc --noEmit for fast type checking
  • Gradual adoption with allowJs: true
  • Path mapping: "@/*": ["src/*"]
  • Declaration files: "declaration": true
  • Use // @ts-expect-error with error messages
Weekly Installs
27
Repository
knoopx/pi
GitHub Stars
16
First Seen
Jan 24, 2026
Installed on
opencode23
gemini-cli23
codex23
claude-code22
cursor22
antigravity21