关于 typescript
面向开发者的 TypeScript 参考技能,提供类型模式、配置和代码质量方面的指导。内容结合语言基础与生产实践、问题排查。
主要功能
- 01基础类型、泛型和工具类型
- 02类型守卫与进阶模式
- 03严格的编译器配置
- 04Lint 与生产就绪指导
适用场景
- 01为应用数据选择类型
- 02配置严格的 TypeScript 项目
- 03排查常见类型错误
MCP 相关
该技能提及可使用 MCP 文档工具获取更全面的 TypeScript 文档。
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill typescript安装后在 Claude Code 中输入/typescript确认已加载。
附带文件quick-ref/generics.mdquick-ref/utility-types.md
详细介绍
TypeScript 核心知识
深入了解:使用
mcp__documentation__fetch_docs并将 technology 设为typescript,获取完整文档。
基本类型
// Primitives
const str: string = 'hello';
const num: number = 42;
const bool: boolean = true;
const arr: number[] = [1, 2, 3];
const tuple: [string, number] = ['hello', 42];
// Objects
interface User {
id: number;
name: string;
email?: string; // Optional
readonly createdAt: Date;
}
type Status = 'active' | 'inactive' | 'pending'; // Union
泛型
// Generic function
function identity<T>(arg: T): T {
return arg;
}
// Generic interface
interface Repository<T> {
find(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
create(data: Omit<T, 'id'>): Promise<T>;
}
// Generic constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
工具类型
Partial<T> // All properties optional
Required<T> // All properties required
Pick<T, K> // Select properties
Omit<T, K> // Remove properties
Record<K, V> // Key-value map
Readonly<T> // All properties readonly
ReturnType<F> // Function return type
Parameters<F> // Function parameters
Awaited<T> // Unwrap Promise
高级模式
// Discriminated unions
type Result<T> =
| { success: true; data: T }
| { success: false; error: Error };
// Type guards
function isUser(obj: unknown): obj is User {
return typeof obj === 'object' && obj !== null && 'id' in obj;
}
// Mapped types
type Nullable<T> = { [K in keyof T]: T[K] | null };
// Template literals
type EventName = `on${Capitalize<string>}`;
配置(tsconfig.json)
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "bundler"
}
}
何时不应使用此技能
| 场景 | 改用 |
|---|---|
| 纯 JavaScript 项目 | javascript 技能 |
| Node.js 运行时内部机制 | nodejs 技能 |
| React 专用类型 | frontend-react 技能 |
| 测试类型断言 | testing-vitest 或 testing-jest 技能 |
| 从架构生成类型 | api-design-openapi 或特定框架技能 |
反模式
| 反模式 | 不良影响 | 正确做法 |
|---|---|---|
到处使用 any | 破坏类型安全 | 使用 unknown 或恰当的类型 |
as 类型断言 | 可能导致运行时错误 | 使用类型守卫或恰当的类型标注 |
| 大型联合类型 | 难以维护 | 使用可辨识联合或品牌类型 |
混用 interface 和 type | 代码库不一致 | 选择一种约定 |
| 忽略 strictNullChecks | 暗藏 null/undefined 错误 | 启用严格模式 |
| 不设边界的索引签名 | 访问不安全 | 使用 Record 或带验证的 Map |
| 泛型深度嵌套 | 类型难以阅读 | 提取中间类型 |
快速故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| "Type 'X' is not assignable to type 'Y'" | 类型不匹配 | 检查类型定义,使用类型守卫 |
| "Property 'x' does not exist on type" | 缺少类型或类型错误 | 添加属性或修正接口 |
| "Cannot find module" | 缺少类型或路径 | 安装 @types 或配置路径 |
| "Object is possibly 'null'" | 已启用 strictNullChecks | 使用可选链或 null 检查 |
| "Type instantiation is excessively deep" | 泛型递归过于复杂 | 简化类型或添加类型边界 |
| "Index signature is missing" | 正在访问动态键 | 使用 Record 或添加索引签名 |
| 构建耗时过长 | 文件过多,未启用增量构建 | 启用增量构建并使用项目引用 |
静态分析与 Lint
官方规则参考
| 工具 | 规则数量 | 文档 |
|---|---|---|
| ESLint | 200+ | https://eslint.org/docs/latest/rules/ |
| TypeScript-ESLint | 100+ | https://typescript-eslint.io/rules/ |
| Biome | 200+ | https://biomejs.dev/linter/rules/ |
| SonarJS | 422 | https://rules.sonarsource.com/javascript/ |
建议启用的关键规则
// eslint.config.js (ESLint 9+)
export default [
{
rules: {
// Prevent bugs
'no-unused-vars': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
// Code quality
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'complexity': ['warn', 10],
'max-depth': ['warn', 4],
}
}
];
推荐配置
| 工具 | 配置 | 命令 |
|---|---|---|
| ESLint | @eslint/js 推荐配置 | npm init @eslint/config |
| TypeScript-ESLint | strict-type-checked | 参见 ts-eslint 文档 |
| Biome | 默认 | npx @biomejs/biome init |
生产就绪
严格配置
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
错误处理
// Type-safe error handling
class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500
) {
super(message);
this.name = 'AppError';
}
}
// Result type pattern
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
async function safeAsync<T>(
promise: Promise<T>
): Promise<Result<T>> {
try {
const data = await promise;
return { success: true, data };
} catch (error) {
return { success: false, error: error as Error };
}
}
// Usage
const result = await safeAsync(fetchUser(id));
if (result.success) {
console.log(result.data);
} else {
console.error(result.error.message);
}
类型安全模式
// Branded types for type safety
type UserId = string & { readonly brand: unique symbol };
type OrderId = string & { readonly brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
// Exhaustive checking
function assertNever(x: never): never {
throw new Error(`Unexpected value: ${x}`);
}
type Status = 'active' | 'inactive' | 'pending';
function handleStatus(status: Status): string {
switch (status) {
case 'active': return 'Active';
case 'inactive': return 'Inactive';
case 'pending': return 'Pending';
default: return assertNever(status);
}
}
// Zod for runtime validation
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(2),
});
type User = z.infer<typeof UserSchema>;
function parseUser(data: unknown): User {
return UserSchema.parse(data);
}
测试
// Type testing with expectTypeOf
import { expectTypeOf, describe, it } from 'vitest';
describe('types', () => {
it('User has correct shape', () => {
expectTypeOf<User>().toMatchTypeOf<{
id: string;
email: string;
name: string;
}>();
});
it('createUser returns User', () => {
expectTypeOf(createUser).returns.toEqualTypeOf<User>();
});
});
// Unit testing with proper types
import { describe, it, expect, vi } from 'vitest';
describe('UserService', () => {
it('fetches user by id', async () => {
const mockUser: User = {
id: '123',
email: '[email protected]',
name: 'Test',
};
const repository = {
findById: vi.fn().mockResolvedValue(mockUser),
};
const service = new UserService(repository);
const result = await service.getUser('123');
expect(result).toEqual(mockUser);
expect(repository.findById).toHaveBeenCalledWith('123');
});
});
性能
// Lazy initialization
class ExpensiveService {
private static instance: ExpensiveService | null = null;
static getInstance(): ExpensiveService {
if (!this.instance) {
this.instance = new ExpensiveService();
}
return this.instance;
}
}
// Memoization with proper types
function memoize<Args extends unknown[], Result>(
fn: (...args: Args) => Result
): (...args: Args) => Result {
const cache = new Map<string, Result>();
return (...args: Args): Result => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key)!;
}
const result = fn(...args);
cache.set(key, result);
return result;
};
}
监控指标
| 指标 | 目标 |
|---|---|
| 类型覆盖率 | > 95% |
| any 使用次数 | 0 次 |
| 构建时间 | < 30s |
| 类型错误 | 0 |
检查清单
- 已启用 strict: true
- 已启用 noUncheckedIndexedAccess
- 未显式使用 any
- 为 ID 使用品牌类型
- 使用 Result 类型处理错误
- 使用 Zod 进行运行时验证
- 使用 expectTypeOf 编写类型测试
- 已生成声明文件
- 已启用源映射
- 使用 typescript-eslint 配置 ESLint
参考文档
深入了解:使用
mcp__documentation__fetch_docs并将 technology 设为typescript,获取完整文档。
评论
支持 Markdown