Loading...
Loading...
Guide for strict TypeScript practices including avoiding any, using proper type annotations, and leveraging TypeScript's type system effectively. Use when working with TypeScript codebases that enforce strict type checking, when you need guidance on type safety patterns, or when encountering type errors. Activates for TypeScript type errors, strict mode violations, or general TypeScript best practices.
npx skill4agent add fluid-tools/claude-skills typescript-strict-modeanyany@typescript-eslint/no-explicit-anyanyanyanyfunction processData(data: any) { ... }
const items: any[] = [];function processData(data: { id: string; name: string }) { ... }
const items: string[] = [];unknownunknownanyfunction handleResponse(response: any) {
return response.data.name; // No type checking!
}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 };
}
// Usage
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 is now typed as User
console.log(data.name);
}
}Record<K, V>const cache: any = {};
cache["key"] = "value";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());
}// 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")!;// 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>;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 Express Request
declare module "express" {
interface Request {
user?: User;
}
}
// Extend environment variables
declare global {
namespace NodeJS {
interface ProcessEnv {
DATABASE_URL: string;
API_KEY: string;
}
}
}anyconst data: any = JSON.parse(jsonString);interface ExpectedData {
id: string;
name: string;
}
const data: unknown = JSON.parse(jsonString);
// Then validate with type guard or schema validation (zod, etc.)any// 'item' has implicit 'any' type
items.map((item) => item.name);items.map((item: Item) => item.name);
// Or ensure 'items' has proper type: 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[] = [];
// or
const items: Array<string> = [];{
"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 deprecatedrule, set@typescript-eslint/no-implicit-any-catchin youruseUnknownInCatchVariables: true(TypeScript 4.4+). This ensures catch clause variables are typed astsconfig.jsoninstead ofunknown.any
anyunknown<T>A | BRecord<K, V>T \| nullT \| undefinedT?(args) => ReturnTypeType[]unknownanyunknown