typescript-best-practices by jwynia/agent-skills
npx skills add https://github.com/jwynia/agent-skills --skill typescript-best-practices指导 AI 代理编写高质量的 TypeScript 代码。此技能提供编码标准、架构模式以及用于分析和搭建脚手架的工具。
在以下情况下使用此技能:
在以下情况下请不要使用此技能:
最大化编译时错误检测:
// 对于未知类型,优先使用 unknown 而非 any
function processInput(data: unknown): string {
if (typeof data === "string") return data;
if (typeof data === "number") return String(data);
throw new Error("Unsupported type");
}
// 公共 API 使用显式返回类型
export function calculateTotal(items: ReadonlyArray<Item>): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// 对字面量类型使用 const 断言
const CONFIG = {
mode: "production",
version: 1,
} as const;
防止意外修改:
// 对对象属性使用 readonly
interface User {
readonly id: string;
readonly email: string;
name: string; // 仅在有意修改时才设为可变
}
// 对集合使用 ReadonlyArray
function processItems(items: ReadonlyArray<Item>): ReadonlyArray<Result> {
return items.map(transform);
}
// 优先使用展开运算符而非直接修改
function updateUser(user: User, name: string): User {
return { ...user, name };
}
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
利用类型系统处理错误:
// 用于可恢复错误的 Result 类型
type Result<T, E = Error> =
| { success: true; value: T }
| { success: false; error: E };
// 类型化的错误类
class ValidationError extends Error {
constructor(
message: string,
readonly field: string,
readonly code: string
) {
super(message);
this.name = "ValidationError";
}
}
// 返回 Result 类型的函数
function parseConfig(input: string): Result<Config, ValidationError> {
try {
const data = JSON.parse(input);
if (!isValidConfig(data)) {
return {
success: false,
error: new ValidationError("Invalid config", "root", "INVALID_FORMAT"),
};
}
return { success: true, value: data };
} catch {
return {
success: false,
error: new ValidationError("Parse failed", "root", "PARSE_ERROR"),
};
}
}
为可维护性构建代码结构:
// 每个文件一个概念
// user.ts - User 类型及相关工具函数
export interface User {
readonly id: string;
readonly email: string;
readonly createdAt: Date;
}
export function createUser(email: string): User {
return {
id: crypto.randomUUID(),
email,
createdAt: new Date(),
};
}
// 显式导出(不使用桶文件通配符)
// index.ts
export { User, createUser } from "./user.ts";
export { validateEmail } from "./validation.ts";
| 类别 | 推荐 | 避免 |
|---|---|---|
| 未知类型 | unknown | any |
| 集合 | ReadonlyArray<T> | 输入使用 T[] |
| 对象 | Readonly<T> | 默认可变 |
| 空值检查 | 可选链 ?. | != null |
| 类型收窄 | 类型守卫 | as 断言 |
| 返回类型 | 导出时显式声明 | 导出时推断 |
| 枚举 | 字符串字面量联合类型 | 数字枚举 |
| 导入 | 命名导入 | 默认导入 |
| 错误 | Result 类型 | 为流程控制抛出错误 |
| 循环 | for...of, .map() | 在数组上使用 for...in |
生成 TypeScript 代码时,请遵循以下模式:
/**
* 模块描述
* @module module-name
*/
// === 类型 ===
export interface ModuleOptions {
readonly setting: string;
}
export interface ModuleResult {
readonly data: unknown;
}
// === 常量 ===
const DEFAULT_OPTIONS: ModuleOptions = {
setting: "default",
};
// === 实现 ===
export function processData(
input: unknown,
options: Partial<ModuleOptions> = {}
): ModuleResult {
const opts = { ...DEFAULT_OPTIONS, ...options };
// 实现
return { data: input };
}
// 优先使用纯函数
function transform(input: Input): Output {
// 无副作用,相同输入 => 相同输出
return { ...input, processed: true };
}
// 显式参数类型
function fetchUser(id: string, options?: FetchOptions): Promise<User> {
// 实现
}
// 对复杂签名使用函数重载
function parse(input: string): ParsedData;
function parse(input: Buffer): ParsedData;
function parse(input: string | Buffer): ParsedData {
// 实现
}
// 对对象形状优先使用接口
interface UserData {
readonly id: string;
readonly email: string;
}
// 对联合类型和交叉类型使用 type
type UserRole = "admin" | "user" | "guest";
type AdminUser = UserData & { readonly role: "admin" };
// 使用 JSDoc 进行文档注释
/**
* API 客户端的配置
* @property baseUrl - API 请求的基础 URL
* @property timeout - 请求超时时间(毫秒)
*/
interface ApiConfig {
readonly baseUrl: string;
readonly timeout?: number;
}
生成代码时避免以下模式:
| 反模式 | 问题 | 解决方案 |
|---|---|---|
any 类型 | 禁用类型检查 | 使用 unknown 并进行收窄 |
as 断言 | 运行时错误 | 使用类型守卫 |
非空断言 ! | 空指针错误 | 可选链 ?. |
| 可变参数 | 意外修改 | Readonly<T> |
| 魔法字符串 | 拼写错误,无自动补全 | 字符串字面量类型 |
| 上帝类 | 难以测试/维护 | 单一职责 |
| 循环依赖 | 构建/运行时问题 | 依赖反转 |
| 索引签名 | 丢失类型信息 | 显式属性 |
详细示例请参阅 references/anti-patterns/common-mistakes.md。
分析 TypeScript 代码的质量问题:
deno run --allow-read scripts/analyze.ts <path> [options]
Options:
--strict 启用所有检查
--json 输出 JSON 以供程序化使用
--fix-hints 显示建议的修复
Examples:
# 分析一个文件
deno run --allow-read scripts/analyze.ts ./src/utils.ts
# 使用严格模式分析目录
deno run --allow-read scripts/analyze.ts ./src --strict
# 为 CI 输出 JSON
deno run --allow-read scripts/analyze.ts ./src --json
从 JSON 数据生成 TypeScript 类型:
deno run --allow-read --allow-write scripts/generate-types.ts <input> [options]
Options:
--name <name> 根类型名称(默认:推断)
--output <path> 输出文件路径
--readonly 生成只读类型
--interface 使用 interface 而非 type
Examples:
# 从 JSON 文件生成
deno run --allow-read scripts/generate-types.ts ./data.json --name Config
# 生成只读接口
deno run --allow-read --allow-write scripts/generate-types.ts ./api-response.json \
--interface --readonly --output ./types/api.ts
创建结构正确的 TypeScript 模块:
deno run --allow-read --allow-write scripts/scaffold-module.ts [options]
Options:
--name <name> 模块名称(必需)
--path <path> 目标目录(默认:./src)
--type <type> 类型:service, util, component
--with-tests 包含测试文件
Examples:
# 创建一个工具模块
deno run --allow-read --allow-write scripts/scaffold-module.ts \
--name "string-utils" --type util
# 创建一个包含测试的服务
deno run --allow-read --allow-write scripts/scaffold-module.ts \
--name "user-service" --type service --with-tests
references/type-system/advanced-types.md - 泛型、条件类型、映射类型references/type-system/type-guards.md - 类型收窄技术references/type-system/utility-types.md - 内置工具类型references/patterns/error-handling.md - Result 类型、类型化错误references/patterns/async-patterns.md - Async/await 最佳实践references/patterns/functional-patterns.md - 不可变性、组合references/patterns/module-patterns.md - 导出、依赖注入references/architecture/project-structure.md - 目录组织references/architecture/api-design.md - 接口设计、版本控制assets/templates/module-template.ts.md - 模块启动模板assets/templates/service-template.ts.md - 服务类模板assets/tsconfig-presets/strict.json - 最高严格度配置assets/tsconfig-presets/recommended.json - 平衡的默认配置每周安装量
180
代码仓库
GitHub 星标数
37
首次出现
Jan 20, 2026
安全审计
安装于
opencode154
gemini-cli147
codex146
github-copilot144
cursor132
amp122
Guide AI agents in writing high-quality TypeScript code. This skill provides coding standards, architecture patterns, and tools for analysis and scaffolding.
Use this skill when:
Do NOT use this skill when:
Maximize compile-time error detection:
// Prefer unknown over any for unknown types
function processInput(data: unknown): string {
if (typeof data === "string") return data;
if (typeof data === "number") return String(data);
throw new Error("Unsupported type");
}
// Explicit return types for public APIs
export function calculateTotal(items: ReadonlyArray<Item>): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Use const assertions for literal types
const CONFIG = {
mode: "production",
version: 1,
} as const;
Prevent accidental mutations:
// Use readonly for object properties
interface User {
readonly id: string;
readonly email: string;
name: string; // Only mutable if intentional
}
// Use ReadonlyArray for collections
function processItems(items: ReadonlyArray<Item>): ReadonlyArray<Result> {
return items.map(transform);
}
// Prefer spreading over mutation
function updateUser(user: User, name: string): User {
return { ...user, name };
}
Use the type system for error handling:
// Result type for recoverable errors
type Result<T, E = Error> =
| { success: true; value: T }
| { success: false; error: E };
// Typed error classes
class ValidationError extends Error {
constructor(
message: string,
readonly field: string,
readonly code: string
) {
super(message);
this.name = "ValidationError";
}
}
// Function with Result return type
function parseConfig(input: string): Result<Config, ValidationError> {
try {
const data = JSON.parse(input);
if (!isValidConfig(data)) {
return {
success: false,
error: new ValidationError("Invalid config", "root", "INVALID_FORMAT"),
};
}
return { success: true, value: data };
} catch {
return {
success: false,
error: new ValidationError("Parse failed", "root", "PARSE_ERROR"),
};
}
}
Structure code for maintainability:
// One concept per file
// user.ts - User type and related utilities
export interface User {
readonly id: string;
readonly email: string;
readonly createdAt: Date;
}
export function createUser(email: string): User {
return {
id: crypto.randomUUID(),
email,
createdAt: new Date(),
};
}
// Explicit exports (no barrel file wildcards)
// index.ts
export { User, createUser } from "./user.ts";
export { validateEmail } from "./validation.ts";
| Category | Prefer | Avoid |
|---|---|---|
| Unknown types | unknown | any |
| Collections | ReadonlyArray<T> | T[] for inputs |
| Objects | Readonly<T> | Mutable by default |
| Null checks | Optional chaining ?. | != null |
When generating TypeScript code, follow these patterns:
/**
* Module description
* @module module-name
*/
// === Types ===
export interface ModuleOptions {
readonly setting: string;
}
export interface ModuleResult {
readonly data: unknown;
}
// === Constants ===
const DEFAULT_OPTIONS: ModuleOptions = {
setting: "default",
};
// === Implementation ===
export function processData(
input: unknown,
options: Partial<ModuleOptions> = {}
): ModuleResult {
const opts = { ...DEFAULT_OPTIONS, ...options };
// Implementation
return { data: input };
}
// Pure functions preferred
function transform(input: Input): Output {
// No side effects, same input = same output
return { ...input, processed: true };
}
// Explicit parameter types
function fetchUser(id: string, options?: FetchOptions): Promise<User> {
// Implementation
}
// Use function overloads for complex signatures
function parse(input: string): ParsedData;
function parse(input: Buffer): ParsedData;
function parse(input: string | Buffer): ParsedData {
// Implementation
}
// Prefer interfaces for object shapes
interface UserData {
readonly id: string;
readonly email: string;
}
// Use type for unions and intersections
type UserRole = "admin" | "user" | "guest";
type AdminUser = UserData & { readonly role: "admin" };
// Document with JSDoc
/**
* Configuration for the API client
* @property baseUrl - The base URL for API requests
* @property timeout - Request timeout in milliseconds
*/
interface ApiConfig {
readonly baseUrl: string;
readonly timeout?: number;
}
Avoid these patterns when generating code:
| Anti-Pattern | Problem | Solution |
|---|---|---|
any type | Disables type checking | Use unknown and narrow |
as assertions | Runtime errors | Use type guards |
Non-null ! | Null pointer errors | Optional chaining ?. |
| Mutable params | Unexpected mutations | Readonly<T> |
See references/anti-patterns/common-mistakes.md for detailed examples.
Analyze TypeScript code for quality issues:
deno run --allow-read scripts/analyze.ts <path> [options]
Options:
--strict Enable all checks
--json Output JSON for programmatic use
--fix-hints Show suggested fixes
Examples:
# Analyze a file
deno run --allow-read scripts/analyze.ts ./src/utils.ts
# Analyze directory with strict mode
deno run --allow-read scripts/analyze.ts ./src --strict
# JSON output for CI
deno run --allow-read scripts/analyze.ts ./src --json
Generate TypeScript types from JSON data:
deno run --allow-read --allow-write scripts/generate-types.ts <input> [options]
Options:
--name <name> Root type name (default: inferred)
--output <path> Output file path
--readonly Generate readonly types
--interface Use interface instead of type
Examples:
# Generate from JSON file
deno run --allow-read scripts/generate-types.ts ./data.json --name Config
# Generate readonly interface
deno run --allow-read --allow-write scripts/generate-types.ts ./api-response.json \
--interface --readonly --output ./types/api.ts
Create properly structured TypeScript modules:
deno run --allow-read --allow-write scripts/scaffold-module.ts [options]
Options:
--name <name> Module name (required)
--path <path> Target directory (default: ./src)
--type <type> Type: service, util, component
--with-tests Include test file
Examples:
# Create a utility module
deno run --allow-read --allow-write scripts/scaffold-module.ts \
--name "string-utils" --type util
# Create a service with tests
deno run --allow-read --allow-write scripts/scaffold-module.ts \
--name "user-service" --type service --with-tests
references/type-system/advanced-types.md - Generics, conditional types, mapped typesreferences/type-system/type-guards.md - Type narrowing techniquesreferences/type-system/utility-types.md - Built-in utility typesreferences/patterns/error-handling.md - Result types, typed errorsreferences/patterns/async-patterns.md - Async/await best practicesreferences/patterns/functional-patterns.md - Immutability, compositionreferences/patterns/module-patterns.md - Exports, dependency injectionreferences/architecture/project-structure.md - Directory organizationreferences/architecture/api-design.md - Interface design, versioningassets/templates/module-template.ts.md - Module starter templateassets/templates/service-template.ts.md - Service class templateassets/tsconfig-presets/strict.json - Maximum strictness configassets/tsconfig-presets/recommended.json - Balanced defaultsWeekly Installs
180
Repository
GitHub Stars
37
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode154
gemini-cli147
codex146
github-copilot144
cursor132
amp122
Node.js 环境配置指南:多环境管理、类型安全与最佳实践
10,500 周安装
| Type narrowing | Type guards | as assertions |
| Return types | Explicit on exports | Inferred on exports |
| Enums | String literal unions | Numeric enums |
| Imports | Named imports | Default imports |
| Errors | Result types | Throwing for flow control |
| Loops | for...of, .map() | for...in on arrays |
| Magic strings | Typos, no autocomplete | String literal types |
| God classes | Hard to test/maintain | Single responsibility |
| Circular deps | Build/runtime issues | Dependency inversion |
| Index signatures | Lose type info | Explicit properties |