typescript-strict-mode by fluid-tools/claude-skills
npx skills add https://github.com/fluid-tools/claude-skills --skill typescript-strict-mode本技能涵盖适用于所有框架的严格 TypeScript 实践。重点在于避免使用 any、使用正确的类型注解,以及利用 TypeScript 的类型系统来编写更安全、更易维护的代码。
any关键规则: 许多代码库都启用了 @typescript-eslint/no-explicit-any 规则。使用 any 将导致构建失败。
为什么 any 是危险的:
any 的替代方案❌ 错误:
function processData(data: any) { ... }
const items: any[] = [];
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
✅ 正确:
function processData(data: { id: string; name: string }) { ... }
const items: string[] = [];
unknownunknown 是 any 的类型安全对应物。它强制你在使用前缩小类型范围。
❌ 错误:
function handleResponse(response: any) {
return response.data.name; // 没有类型检查!
}
✅ 正确:
function handleResponse(response: unknown) {
if (
typeof response === "object" &&
response !== null &&
"data" in response &&
typeof (response as { data: unknown }).data === "object"
) {
const data = (response as { data: { name: string } }).data;
return data.name;
}
throw new Error("Invalid response format");
}
❌ 错误:
function wrapValue(value: any): { wrapped: any } {
return { wrapped: value };
}
✅ 正确:
function wrapValue<T>(value: T): { wrapped: T } {
return { wrapped: value };
}
// 用法
const wrappedString = wrapValue("hello"); // { wrapped: string }
const wrappedNumber = wrapValue(42); // { wrapped: number }
❌ 错误:
function handleInput(input: any) {
if (typeof input === 'string') { ... }
if (typeof input === 'number') { ... }
}
✅ 正确:
function handleInput(input: string | number) {
if (typeof input === 'string') { ... }
if (typeof input === 'number') { ... }
}
interface User {
id: string;
name: string;
email: string;
}
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value &&
"email" in value &&
typeof (value as User).id === "string" &&
typeof (value as User).name === "string" &&
typeof (value as User).email === "string"
);
}
function processUser(data: unknown) {
if (isUser(data)) {
// data 现在被类型化为 User
console.log(data.name);
}
}
Record<K, V>❌ 错误:
const cache: any = {};
cache["key"] = "value";
✅ 正确:
const cache: Record<string, string> = {};
cache["key"] = "value";
// 或者使用特定键
const userSettings: Record<"theme" | "language", string> = {
theme: "dark",
language: "en",
};
interface Config {
name: string;
version: string;
[key: string]: string | number | boolean; // 附加属性
}
const config: Config = {
name: "my-app",
version: "1.0.0",
debug: true,
port: 3000,
};
// 表单事件
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// ...
};
// 输入事件
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
// ...
};
// 点击事件
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
// ...
};
// 键盘事件
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') { ... }
};
// 焦点事件
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
// ...
};
// 通用 DOM 事件
document.addEventListener('click', (e: MouseEvent) => { ... });
document.addEventListener('keydown', (e: KeyboardEvent) => { ... });
document.addEventListener('submit', (e: SubmitEvent) => { ... });
// 返回 Promise 的函数
async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// 箭头函数变体
const fetchUser = async (id: string): Promise<User> => {
const response = await fetch(`/api/users/${id}`);
return response.json();
};
// 带有显式类型的 Promise
const userPromise: Promise<User> = fetchUser("123");
// 使用类型推断进行 await
const user = await fetchUser("123"); // User
// 包含多种类型的 Promise.all
const [user, posts] = await Promise.all([fetchUser("123"), fetchPosts("123")]); // [User, Post[]]
// 类型化的回调参数
function processItems(
items: string[],
callback: (item: string, index: number) => void
) {
items.forEach(callback);
}
// 替代方案:提取类型
type ItemCallback = (item: string, index: number) => void;
function processItems(items: string[], callback: ItemCallback) {
items.forEach(callback);
}
// 针对不同输入/输出类型的函数重载
function parse(input: string): object;
function parse(input: Buffer): object;
function parse(input: string | Buffer): object {
if (typeof input === "string") {
return JSON.parse(input);
}
return JSON.parse(input.toString());
}
仅在你比 TypeScript 知道更多信息时使用类型断言:
// DOM 元素断言(当你知道元素类型时)
const input = document.getElementById("email") as HTMLInputElement;
// 响应数据断言(当你信任 API 时)
const data = (await response.json()) as ApiResponse;
// 非空断言(当你知道它不为 null 时)
const element = document.querySelector(".button")!;
警告: 类型断言会绕过 TypeScript 的检查。尽可能优先使用类型守卫。
// Partial - 所有属性可选
type PartialUser = Partial<User>;
// Required - 所有属性必需
type RequiredUser = Required<User>;
// Pick - 选择特定属性
type UserName = Pick<User, "name" | "email">;
// Omit - 排除特定属性
type UserWithoutId = Omit<User, "id">;
// Readonly - 不可变属性
type ReadonlyUser = Readonly<User>;
// Record - 创建对象类型
type UserMap = Record<string, User>;
// ReturnType - 提取函数返回类型
type FetchUserReturn = ReturnType<typeof fetchUser>;
// Parameters - 提取函数参数
type FetchUserParams = Parameters<typeof fetchUser>;
处理多个相关类型的模式:
type Result<T> = { success: true; data: T } | { success: false; error: string };
function handleResult<T>(result: Result<T>) {
if (result.success) {
// TypeScript 知道此处 result.data 存在
console.log(result.data);
} else {
// TypeScript 知道此处 result.error 存在
console.error(result.error);
}
}
在不修改原始类型的情况下扩展现有类型:
// 扩展 Express Request
declare module "express" {
interface Request {
user?: User;
}
}
// 扩展环境变量
declare global {
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
API_KEY: string;
}
}
}
any❌ 错误:
const data: any = JSON.parse(jsonString);
✅ 正确:
interface ExpectedData {
id: string;
name: string;
}
const data: unknown = JSON.parse(jsonString);
// 然后使用类型守卫或模式验证(zod 等)进行验证
any❌ 错误:
// 'item' 具有隐式 'any' 类型
items.map((item) => item.name);
✅ 正确:
items.map((item: Item) => item.name);
// 或者确保 'items' 具有正确的类型:Item[]
❌ 错误:
function getValue(obj: any, key: string) {
return obj[key];
}
✅ 正确:
function getValue<T extends Record<string, unknown>, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
❌ 错误:
const items = []; // any[]
✅ 正确:
const items: string[] = [];
// 或者
const items: Array<string> = [];
对于严格的 TypeScript,请启用以下规则:
{
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/strict-boolean-expressions": "warn",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-unsafe-member-access": "error",
"@typescript-eslint/no-unsafe-call": "error",
"@typescript-eslint/no-unsafe-return": "error"
}
}
注意: 与其使用已弃用的
@typescript-eslint/no-implicit-any-catch规则,不如在你的tsconfig.json中设置useUnknownInCatchVariables: true(TypeScript 4.4+)。这确保了 catch 子句变量被类型化为unknown而不是any。
| 代替 any | 使用 | | ---------------- | ------------------------ | --- | | 未知数据 | unknown | | 灵活类型 | 泛型 <T> | | 多种类型 | 联合 A | B | | 动态键 | Record<K, V> | | 可为空 | T \| null | | 可选 | T \| undefined 或 T? | | 回调 | (args) => ReturnType | | 空数组 | Type[] | | JSON 数据 | unknown + 类型守卫 |
any - 它破坏了 TypeScript 的目的unknown 处理真正未知的类型,然后用类型守卫缩小范围每周安装次数
81
代码仓库
GitHub 星标数
16
首次出现
2026年1月20日
安全审计
已安装于
gemini-cli67
opencode67
codex66
cursor63
github-copilot62
claude-code60
This skill covers strict TypeScript practices applicable across all frameworks. It focuses on avoiding any, using proper type annotations, and leveraging TypeScript's type system for safer, more maintainable code.
anyCRITICAL RULE: Many codebases have @typescript-eslint/no-explicit-any enabled. Using any will cause build failures.
Whyany is dangerous:
any❌ WRONG:
function processData(data: any) { ... }
const items: any[] = [];
✅ CORRECT:
function processData(data: { id: string; name: string }) { ... }
const items: string[] = [];
unknown When Type is Truly Unknownunknown is the type-safe counterpart to any. It forces you to narrow the type before using it.
❌ WRONG:
function handleResponse(response: any) {
return response.data.name; // No type checking!
}
✅ CORRECT:
function handleResponse(response: unknown) {
if (
typeof response === "object" &&
response !== null &&
"data" in response &&
typeof (response as { data: unknown }).data === "object"
) {
const data = (response as { data: { name: string } }).data;
return data.name;
}
throw new Error("Invalid response format");
}
❌ WRONG:
function wrapValue(value: any): { wrapped: any } {
return { wrapped: value };
}
✅ CORRECT:
function wrapValue<T>(value: T): { wrapped: T } {
return { wrapped: value };
}
// Usage
const wrappedString = wrapValue("hello"); // { wrapped: string }
const wrappedNumber = wrapValue(42); // { wrapped: number }
❌ WRONG:
function handleInput(input: any) {
if (typeof input === 'string') { ... }
if (typeof input === 'number') { ... }
}
✅ CORRECT:
function handleInput(input: string | number) {
if (typeof input === 'string') { ... }
if (typeof input === 'number') { ... }
}
interface User {
id: string;
name: string;
email: string;
}
function isUser(value: unknown): value is User {
return (
typeof value === "object" &&
value !== null &&
"id" in value &&
"name" in value &&
"email" in value &&
typeof (value as User).id === "string" &&
typeof (value as User).name === "string" &&
typeof (value as User).email === "string"
);
}
function processUser(data: unknown) {
if (isUser(data)) {
// data is now typed as User
console.log(data.name);
}
}
Record<K, V> for Dynamic Objects❌ WRONG:
const cache: any = {};
cache["key"] = "value";
✅ CORRECT:
const cache: Record<string, string> = {};
cache["key"] = "value";
// Or with specific keys
const userSettings: Record<"theme" | "language", string> = {
theme: "dark",
language: "en",
};
interface Config {
name: string;
version: string;
[key: string]: string | number | boolean; // Additional properties
}
const config: Config = {
name: "my-app",
version: "1.0.0",
debug: true,
port: 3000,
};
// Form events
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// ...
};
// Input events
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
// ...
};
// Click events
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
// ...
};
// Keyboard events
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') { ... }
};
// Focus events
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
// ...
};
// Generic DOM events
document.addEventListener('click', (e: MouseEvent) => { ... });
document.addEventListener('keydown', (e: KeyboardEvent) => { ... });
document.addEventListener('submit', (e: SubmitEvent) => { ... });
// Function returning a promise
async function fetchUser(id: string): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// Arrow function variant
const fetchUser = async (id: string): Promise<User> => {
const response = await fetch(`/api/users/${id}`);
return response.json();
};
// Promise with explicit type
const userPromise: Promise<User> = fetchUser("123");
// Awaiting with type inference
const user = await fetchUser("123"); // User
// Promise.all with multiple types
const [user, posts] = await Promise.all([fetchUser("123"), fetchPosts("123")]); // [User, Post[]]
// Typed callback parameter
function processItems(
items: string[],
callback: (item: string, index: number) => void
) {
items.forEach(callback);
}
// Alternative: Extract the type
type ItemCallback = (item: string, index: number) => void;
function processItems(items: string[], callback: ItemCallback) {
items.forEach(callback);
}
// Function overloads for different input/output types
function parse(input: string): object;
function parse(input: Buffer): object;
function parse(input: string | Buffer): object {
if (typeof input === "string") {
return JSON.parse(input);
}
return JSON.parse(input.toString());
}
Use type assertions only when you know more than TypeScript:
// DOM element assertion (when you know the element type)
const input = document.getElementById("email") as HTMLInputElement;
// Response data assertion (when you trust the API)
const data = (await response.json()) as ApiResponse;
// Non-null assertion (when you know it's not null)
const element = document.querySelector(".button")!;
Warning: Type assertions bypass TypeScript's checks. Prefer type guards when possible.
// Partial - all properties optional
type PartialUser = Partial<User>;
// Required - all properties required
type RequiredUser = Required<User>;
// Pick - select specific properties
type UserName = Pick<User, "name" | "email">;
// Omit - exclude specific properties
type UserWithoutId = Omit<User, "id">;
// Readonly - immutable properties
type ReadonlyUser = Readonly<User>;
// Record - create object type
type UserMap = Record<string, User>;
// ReturnType - extract function return type
type FetchUserReturn = ReturnType<typeof fetchUser>;
// Parameters - extract function parameters
type FetchUserParams = Parameters<typeof fetchUser>;
Pattern for handling multiple related types:
type Result<T> = { success: true; data: T } | { success: false; error: string };
function handleResult<T>(result: Result<T>) {
if (result.success) {
// TypeScript knows result.data exists here
console.log(result.data);
} else {
// TypeScript knows result.error exists here
console.error(result.error);
}
}
Extend existing types without modifying original:
// Extend Express Request
declare module "express" {
interface Request {
user?: User;
}
}
// Extend environment variables
declare global {
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
API_KEY: string;
}
}
}
any for JSON Data❌ WRONG:
const data: any = JSON.parse(jsonString);
✅ CORRECT:
interface ExpectedData {
id: string;
name: string;
}
const data: unknown = JSON.parse(jsonString);
// Then validate with type guard or schema validation (zod, etc.)
any in Callbacks❌ WRONG:
// 'item' has implicit 'any' type
items.map((item) => item.name);
✅ CORRECT:
items.map((item: Item) => item.name);
// Or ensure 'items' has proper type: Item[]
❌ WRONG:
function getValue(obj: any, key: string) {
return obj[key];
}
✅ CORRECT:
function getValue<T extends Record<string, unknown>, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
❌ WRONG:
const items = []; // any[]
✅ CORRECT:
const items: string[] = [];
// or
const items: Array<string> = [];
For strict TypeScript, enable these rules:
{
"rules": {
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/strict-boolean-expressions": "warn",
"@typescript-eslint/no-unsafe-assignment": "error",
"@typescript-eslint/no-unsafe-member-access": "error",
"@typescript-eslint/no-unsafe-call": "error",
"@typescript-eslint/no-unsafe-return": "error"
}
}
Note : Instead of the deprecated
@typescript-eslint/no-implicit-any-catchrule, setuseUnknownInCatchVariables: truein yourtsconfig.json(TypeScript 4.4+). This ensures catch clause variables are typed asunknowninstead ofany.
| Instead of any | Use | | ---------------- | ------------------------ | --- | | Unknown data | unknown | | Flexible type | Generics <T> | | Multiple types | Union A | B | | Dynamic keys | Record<K, V> | | Nullable | T \| null | | Optional | T \| undefined or T? | | Callback | (args) => ReturnType | | Empty array | Type[] | | JSON data | unknown + type guard |
any - it defeats TypeScript's purposeunknown for truly unknown types, then narrow with type guardsWeekly Installs
81
Repository
GitHub Stars
16
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
gemini-cli67
opencode67
codex66
cursor63
github-copilot62
claude-code60
Node.js 环境配置指南:多环境管理、类型安全与最佳实践
10,500 周安装