AgentSkillsCN

typescript

熟练运用 TypeScript 的严格模式与最佳实践。触发条件:当您编写 TypeScript 代码时——例如类型定义、接口声明、泛型使用。

SKILL.md
--- frontmatter
name: typescript
description: >
  TypeScript strict patterns and best practices.
  Trigger: When writing TypeScript code - types, interfaces, generics.
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task

TypeScript Best Practices

This document outlines best practices for using TypeScript in Astro and Vue projects, focusing on types, interfaces, generics, and utility types.

Const Types Pattern (REQUIRED)

typescript
// ✅ ALWAYS: Create const object first, then extract type
const STATUS = {
  ACTIVE: "active",
  INACTIVE: "inactive",
  PENDING: "pending",
} as const;

type Status = (typeof STATUS)[keyof typeof STATUS];

// ❌ NEVER: Direct union types
type Status = "active" | "inactive" | "pending";

Why? Single source of truth, runtime values, autocomplete, easier refactoring.

Flat Interfaces (REQUIRED)

typescript
// ✅ ALWAYS: One level depth, nested objects → dedicated interface
interface UserAddress {
  street: string;
  city: string;
}

interface User {
  id: string;
  name: string;
  address: UserAddress;  // Reference, not inline
}

interface Admin extends User {
  permissions: string[];
}

// ❌ NEVER: Inline nested objects
interface User {
  address: { street: string; city: string };  // NO!
}

Never Use any

typescript
// ✅ Use unknown for truly unknown types
function parse(input: unknown): User {
  if (isUser(input)) return input;
  throw new Error("Invalid input");
}

// ✅ Use generics for flexible types
function first<T>(arr: T[]): T | undefined {
  return arr[0];
}

// ❌ NEVER
function parse(input: any): any { }

Utility Types

typescript
Pick<User, "id" | "name">     // Select fields
Omit<User, "id">              // Exclude fields
Partial<User>                 // All optional
Required<User>                // All required
Readonly<User>                // All readonly
Record<string, User>          // Object type
Extract<Union, "a" | "b">     // Extract from union
Exclude<Union, "a">           // Exclude from union
NonNullable<T | null>         // Remove null/undefined
ReturnType<typeof fn>         // Function return type
Parameters<typeof fn>         // Function params tuple

Examples

typescript
// Pick: select only specific fields (e.g. for form payloads, previews)
type UserPreview = Pick<User, "id" | "name">;
// { id: string; name: string }

// Omit: remove fields (e.g. hide sensitive data for public types)
type PublicUser = Omit<User, "password">;
// { id: string; name: string; ... }

// Partial: make all fields optional (e.g. update forms, patch payloads)
type UserUpdate = Partial<User>;
// { id?: string; name?: string; ... }

// Required: make all fields required (e.g. validation, strict objects)
type StrictUser = Required<User>;
// { id: string; name: string; ... }

// Readonly: prevent mutation (e.g. config, constants)
type ImmutableUser = Readonly<User>;
// { readonly id: string; ... }

// Record: dictionary/map with known value type (e.g. id → user lookup)
type UserMap = Record<string, User>;
// { [id: string]: User }

// Extract: filter union to allowed members (e.g. only certain values)
type Allowed = Extract<"a" | "b" | "c", "a" | "b">;
// "a" | "b"

// Exclude: remove members from union (e.g. blacklist values)
type NotA = Exclude<"a" | "b" | "c", "a">;
// "b" | "c"

// NonNullable: remove null/undefined (e.g. for strict values)
type Name = NonNullable<string | null | undefined>;
// string

// ReturnType: get function return type (e.g. for API responses)
function getUser(): Promise<User> { /* ... */ }
type UserPromise = ReturnType<typeof getUser>;
// Promise<User>

// Parameters: get function parameter tuple (e.g. for wrappers)
function setUser(id: string, user: User) {}
type SetUserParams = Parameters<typeof setUser>;
// [id: string, user: User]

Type Guards

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

Import Types

typescript
import type { User } from "./types";
import { createUser, type Config } from "./utils";