mcpField
S
strict-typing

strict-typing

github.com/troykelly开发1238 次安装41 周前更新
代码仓库

关于 strict-typing

strict-typing 是面向多种静态类型语言开发者的编码技能,要求显式准确地标注类型,避免类型逃逸,并通过严格配置和运行时校验支持可靠代码。

主要功能

  1. 01避免 any、unknown 等类型逃逸
  2. 02要求函数参数与返回值有类型
  3. 03建议严格类型检查配置
  4. 04为动态数据定义类型并校验
  5. 05为缺少类型的库补充定义

适用场景

  1. 01编写 TypeScript 或 Python 类型安全代码
  2. 02处理 API 响应和解析后的 JSON
  3. 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