关于 strict-typing
strict-typing 是面向多种静态类型语言开发者的编码技能,要求显式准确地标注类型,避免类型逃逸,并通过严格配置和运行时校验支持可靠代码。
主要功能
- 01避免 any、unknown 等类型逃逸
- 02要求函数参数与返回值有类型
- 03建议严格类型检查配置
- 04为动态数据定义类型并校验
- 05为缺少类型的库补充定义
适用场景
- 01编写 TypeScript 或 Python 类型安全代码
- 02处理 API 响应和解析后的 JSON
- 03使用缺少类型声明的第三方库
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ troykelly/ claude-skills --skill strict-typing安装后在 Claude Code 中输入/strict-typing确认已加载。
详细介绍
严格类型
概述
不要使用 any 类型。不要让 unknown 类型逃逸。所有内容都必须有完整类型。
核心原则: 类型是由编译器验证的文档。
此技能适用于: TypeScript、Python(带类型提示)、Go、Rust、Java、C# 以及任何带类型的语言。
规则
NEVER use any, unknown, or equivalent type escapes.
ALWAYS provide explicit, accurate types.
TAKE EXTRA TIME if needed to type correctly.
TypeScript 特定内容
禁止的模式
// NEVER
const data: any = fetchData();
const items: unknown[] = parseItems();
function process(input: any): any { }
const config = {} as any;
// @ts-ignore
// @ts-expect-error (unless truly necessary with documentation)
必需的模式
// ALWAYS
interface UserData {
id: string;
name: string;
email: string;
}
const data: UserData = fetchData();
function process<T extends Processable>(input: T): ProcessResult<T> {
// ...
}
配置
确保 tsconfig.json 启用了严格模式:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true
}
}
处理第三方类型
缺少库类型时:
// Create type definitions
declare module 'untyped-library' {
export interface Config {
option1: string;
option2: number;
}
export function init(config: Config): void;
}
或者为 DefinitelyTyped 贡献类型。
处理动态数据
对于 API 响应或解析后的 JSON:
// Define expected shape
interface ApiResponse {
users: User[];
pagination: Pagination;
}
// Use type guard for runtime validation
function isApiResponse(data: unknown): data is ApiResponse {
return (
typeof data === 'object' &&
data !== null &&
'users' in data &&
Array.isArray((data as ApiResponse).users)
);
}
// Use with validation
const response = await fetch('/api/users');
const data: unknown = await response.json();
if (!isApiResponse(data)) {
throw new Error('Invalid API response');
}
// data is now typed as ApiResponse
使用 Zod 进行运行时验证
import { z } from 'zod';
const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
// Parse and validate
const user = UserSchema.parse(unknownData);
// user is now typed as User
Python 特定内容
禁止的模式
# NEVER
def process(data): # Missing type hints
pass
def fetch() -> Any: # Using Any
pass
from typing import Any
result: Any = compute()
必需的模式
# ALWAYS
from typing import TypeVar, Generic, Protocol
from dataclasses import dataclass
@dataclass
class User:
id: str
name: str
email: str
def process(data: User) -> ProcessResult:
...
T = TypeVar('T', bound='Processable')
def transform(items: list[T]) -> list[T]:
...
配置
使用严格的 mypy 设置:
# mypy.ini
[mypy]
strict = True
disallow_any_generics = True
disallow_untyped_defs = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
warn_redundant_casts = True
warn_unused_ignores = True
Go 特定内容
Go 是静态类型语言,但要避免:
// AVOID
interface{} // empty interface
any // Go 1.18+ alias for interface{}
// PREFER
type specific interfaces or concrete types
确实需要 interface{} 时,请说明原因并添加类型断言。
类型难以处理时
如果类型定义似乎不可能:
第 1 步:审视设计
Is the type hard to express because the design is complex?
→ Consider simplifying the design
第 2 步:使用泛型
// Instead of any
function process<T>(input: T): T {
return input;
}
第 3 步:使用联合类型
// Instead of any for multiple types
type Input = string | number | User;
function process(input: Input): void {
if (typeof input === 'string') {
// input is string
} else if (typeof input === 'number') {
// input is number
} else {
// input is User
}
}
第 4 步:创建类型守卫
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value
);
}
第 5 步:记录并说明理由(最后手段)
如果确实无法避免使用 any(极其罕见):
// JUSTIFIED: Third-party library `foo` has no types and
// creating accurate types requires reverse-engineering
// the entire library. See issue #123 for type contribution.
// TODO(#456): Remove when @types/foo is available
const result: any = thirdPartyCall();
这种情况应该极其罕见。
时间投入
正确处理类型需要时间,这是可以接受的。
| 情况 | 可接受的时间 |
|---|---|
| 简单接口 | 5 分钟 |
| 复杂泛型 | 30 分钟 |
| 类型守卫 | 15 分钟 |
| 库类型 | 1 小时 |
如果类型处理耗时更久,可能需要重新考虑设计。
检查清单
提交代码前:
- 不使用
any类型 - 不使用没有类型守卫的
unknown - 不使用
@ts-ignore或# type: ignore - 所有函数的参数都有类型
- 所有函数都有带类型的返回值
- 所有公开的接口/类型都已导出
- 类型配置为严格模式
不接受的常见借口
| 借口 | 回应 |
|---|---|
| “这只是临时的” | 临时代码会变成永久代码。现在就为它添加类型。 |
| “我稍后再修复类型” | 以后永远不会到来。现在就为它添加类型。 |
| “用 any 更快” | 技术债只会拖慢速度。现在就为它添加类型。 |
| “这个库没有类型” | 创建类型或使用 Zod。 |
| “它太复杂,无法添加类型” | 简化设计。 |
集成
此技能由以下流程应用:
issue-driven-development- 第 7 步
此技能可确保:
- 代码自带文档
- 编译时捕获错误
- 安全重构
- 更好的 IDE 支持
评论
支持 Markdown