typescript-type-system

安装量: 45
排名: #16544

安装

npx skills add https://github.com/thebushidocollective/han --skill typescript-type-system

Master TypeScript's type system features to write type-safe code. This skill focuses exclusively on TypeScript language capabilities.

TypeScript Compiler

# Type check without emitting files
tsc --noEmit

# Type check with specific config
tsc --noEmit -p tsconfig.json

# Show compiler version
tsc --version

# Watch mode for development
tsc --noEmit --watch

Strict Mode Configuration

tsconfig.json strict mode options:

{
  "compilerOptions": {
    "strict": true,                           // Enables all strict
    "noImplicitAny": true,                    // Error on 'any'
    "strictNullChecks": true,                 // null must be explicit
    "strictFunctionTypes": true,              // Stricter function types
    "strictBindCallApply": true,              // Strict bind/call/apply
    "strictPropertyInitialization": true,     // Class init required
    "noImplicitThis": true,                   // Error on 'this' any
    "alwaysStrict": true,                     // Parse strict mode
    "useUnknownInCatchVariables": true        // Catch is 'unknown'
  }
}

Essential Compiler Options

{
  "compilerOptions": {
    // Type Checking
    "exactOptionalPropertyTypes": true,       // Distinguish undefined from missing
    "noFallthroughCasesInSwitch": true,      // Prevent fallthrough in switch
    "noImplicitOverride": true,               // Require 'override' keyword
    "noImplicitReturns": true,                // All code paths must return
    "noPropertyAccessFromIndexSignature": true, // Require bracket notation for index
    "noUncheckedIndexedAccess": true,         // Index signatures return T | undefined
    "noUnusedLocals": true,                   // Error on unused local variables
    "noUnusedParameters": true,               // Error on unused parameters

    // Module Resolution
    "moduleResolution": "bundler",            // Modern bundler resolution
    "resolveJsonModule": true,                // Import JSON files
    "allowImportingTsExtensions": true,       // Import .ts/.tsx files
    "allowSyntheticDefaultImports": true,     // Allow default imports from modules
    "esModuleInterop": true,                  // Emit helpers for CommonJS interop

    // Emit
    "declaration": true,                      // Generate .d.ts files
    "declarationMap": true,                   // Source maps for .d.ts
    "sourceMap": true,                        // Generate .map files
    "removeComments": false,                  // Preserve comments in output
    "importHelpers": true,                    // Import helpers from tslib

    // Interop Constraints
    "isolatedModules": true,                  // Each file can be transpiled separately
    "allowArbitraryExtensions": true,         // Allow imports with any extension
    "verbatimModuleSyntax": false,            // Preserve import/export syntax

    // Skip Checks
    "skipLibCheck": true                      // Skip .d.ts file checking
  }
}

Advanced Type Patterns

Union and Intersection Types

// Union types (OR)
type Status = "pending" | "active" | "completed";
type ID = string | number;
type Result = Success | Error;

// Intersection types (AND)
type User = Person & Employee;
type Props = BaseProps & { extended: true };

// Discriminated unions
type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; size: number }
  | { kind: "rectangle"; width: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "square":
      return shape.size ** 2;
    case "rectangle":
      return shape.width * shape.height;
  }
}

Generics

// Basic generics
function identity<T>(value: T): T {
  return value;
}

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

// Multiple type parameters
function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

// Generic interfaces
interface Repository<T> {
  find(id: string): Promise<T | null>;
  save(entity: T): Promise<T>;
  delete(id: string): Promise<void>;
}

// Generic classes
class DataStore<T extends { id: string }> {
  private items = new Map<string, T>();

  add(item: T): void {
    this.items.set(item.id, item);
  }

  get(id: string): T | undefined {
    return this.items.get(id);
  }
}

// Default type parameters
type Response<T = unknown> = {
  data: T;
  status: number;
};

Conditional Types

// Basic conditional type
type IsString<T> = T extends string ? true : false;

// Distributive conditional types
type Extract<T, U> = T extends U ? T : never;
type Exclude<T, U> = T extends U ? never : T;

// Infer keyword
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

// Nested conditionals
type Flatten<T> = T extends Array<infer U> ? U : T;
type DeepFlatten<T> = T extends Array<infer U> ? DeepFlatten<U> : T;

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

Mapped Types

// Make all properties optional
type Partial<T> = {
  [P in keyof T]?: T[P];
};

// Make all properties required
type Required<T> = {
  [P in keyof T]-?: T[P];
};

// Make all properties readonly
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

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

// Omit specific properties
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

// Transform property types
type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

// Key remapping in mapped types
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

// Filter properties by type
type PickByType<T, U> = {
  [P in keyof T as T[P] extends U ? P : never]: T[P];
};

Template Literal Types

// Basic template literals
type EventName = "click" | "focus" | "blur";
type Handler = `on${Capitalize<EventName>}`; // "onClick" | "onFocus" | "onBlur"

// Combining template literals
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type Endpoint = `/api/${string}`;
type Route = `${HTTPMethod} ${Endpoint}`;

// Extract pattern from template
type ExtractRouteParams<T extends string> =
  T extends `${string}:${infer Param}/${infer Rest}`
    ? Param | ExtractRouteParams<Rest>
    : T extends `${string}:${infer Param}`
    ? Param
    : never;

type Params = ExtractRouteParams<"/users/:userId/posts/:postId">; // "userId" | "postId"

// Uppercase/Lowercase/Capitalize/Uncapitalize
type UppercaseKeys<T> = {
  [K in keyof T as Uppercase<string & K>]: T[K];
};

Type Narrowing

Type Guards

// typeof type guards
function process(value: string | number) {
  if (typeof value === "string") {
    return value.toUpperCase(); // value is string
  }
  return value.toFixed(2); // value is number
}

// instanceof type guards
class Dog {
  bark() {}
}
class Cat {
  meow() {}
}

function makeSound(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    animal.bark(); // animal is Dog
  } else {
    animal.meow(); // animal is Cat
  }
}

// in operator narrowing
type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim(); // animal is Fish
  } else {
    animal.fly(); // animal is Bird
  }
}

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

function isUser(obj: unknown): obj is { name: string; age: number } {
  return (
    typeof obj === "object" &&
    obj !== null &&
    "name" in obj &&
    "age" in obj &&
    typeof obj.name === "string" &&
    typeof obj.age === "number"
  );
}

// Assertion functions
function assert(condition: unknown, msg?: string): asserts condition {
  if (!condition) {
    throw new Error(msg);
  }
}

function assertIsString(value: unknown): asserts value is string {
  if (typeof value !== "string") {
    throw new Error("Not a string");
  }
}

Discriminated Unions

// Using literal types as discriminators
type NetworkState =
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; error: Error };

function handleNetwork(state: NetworkState) {
  switch (state.status) {
    case "loading":
      return "Loading...";
    case "success":
      return state.data; // data is available
    case "error":
      return state.error.message; // error is available
  }
}

// Multiple discriminants
type Response =
  | { kind: "ok"; status: 200; data: string }
  | { kind: "redirect"; status: 301 | 302; location: string }
  | { kind: "error"; status: 400 | 500; message: string };

Truthiness Narrowing

function printAll(strs: string | string[] | null) {
  if (strs && typeof strs === "object") {
    // strs is string[]
    for (const s of strs) {
      console.log(s);
    }
  } else if (typeof strs === "string") {
    // strs is string
    console.log(strs);
  }
}

Utility Types

Built-in Utility Types

// Partial - Make all properties optional
type User = { name: string; age: number };
type PartialUser = Partial<User>; // { name?: string; age?: number }

// Required - Make all properties required
type RequiredUser = Required<PartialUser>; // { name: string; age: number }

// Readonly - Make all properties readonly
type ReadonlyUser = Readonly<User>;
// { readonly name: string; readonly age: number }

// Record - Construct object type with keys K and values T
type PageInfo = Record<"home" | "about" | "contact", { title: string }>;

// Pick - Pick properties from type
type UserName = Pick<User, "name">; // { name: string }

// Omit - Omit properties from type
type UserWithoutAge = Omit<User, "age">; // { name: string }

// Exclude - Exclude types from union
type T = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

// Extract - Extract types from union
type T2 = Extract<"a" | "b" | "c", "a" | "f">; // "a"

// NonNullable - Remove null and undefined
type T3 = NonNullable<string | null | undefined>; // string

// ReturnType - Get return type of function
function f() { return { x: 10, y: 3 }; }
type P = ReturnType<typeof f>; // { x: number; y: number }

// Parameters - Get parameter types as tuple
function f2(a: string, b: number) {}
type P2 = Parameters<typeof f2>; // [string, number]

// ConstructorParameters - Get constructor parameter types
class C {
  constructor(a: string, b: number) {}
}
type CP = ConstructorParameters<typeof C>; // [string, number]

// InstanceType - Get instance type of constructor
type CT = InstanceType<typeof C>; // C

// Awaited - Get type returned by Promise
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number

Type Assertions and Casting

// Type assertions (angle-bracket syntax - avoid in JSX)
let someValue: unknown = "this is a string";
let strLength: number = (<string>someValue).length;

// Type assertions (as syntax - preferred)
let strLength2: number = (someValue as string).length;

// Non-null assertion operator
function liveDangerously(x?: number | null) {
  console.log(x!.toFixed()); // x is definitely not null/undefined
}

// Const assertions
let x = "hello" as const; // type is "hello", not string
let y = [10, 20] as const; // type is readonly [10, 20]
let z = { text: "hello" } as const; // type is { readonly text: "hello" }

// Double assertion (escape hatch - use sparingly)
const a = (expr as unknown) as T;

// Satisfies operator (check type without widening)
type Color = { r: number; g: number; b: number } | string;

const red = { r: 255, g: 0, b: 0 } satisfies Color;
const blue = "#0000FF" satisfies Color;

Type-Only Imports and Exports

// Import only types (erased at runtime)
import type { User, Product } from "./types";
import type * as Types from "./types";

// Mixed imports
import { type User, createUser } from "./user";

// Export only types
export type { User, Product };
export type * from "./types";

// Inline type imports (verbatimModuleSyntax: false)
import { type User } from "./user";

Index Signatures and Mapped Types

// Basic index signature
interface StringMap {
  [key: string]: string;
}

// Numeric index signature
interface NumberArray {
  [index: number]: number;
}

// Index signature with known properties
interface Dictionary {
  [key: string]: string;
  name: string; // OK: string is assignable to string
}

// Template literal in index signature
interface Events {
  [key: `on${string}`]: (event: Event) => void;
}

// Accessing with index signatures (with noUncheckedIndexedAccess)
interface Data {
  [key: string]: number;
}

const data: Data = {};
const value = data["key"]; // type is number | undefined

// Avoiding index signature with Record
type SafeData = Record<string, number>;

Advanced Patterns

Branded Types

// Nominal typing via branding type Brand = K & { __brand: T };

type <span class="token class-

返回排行榜