Agent skill
typescript-strict
TypeScript strict mode patterns and best practices. Index access, literal types, null checks, generics, type inference. Use when working with TypeScript files.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/typescript-strict
SKILL.md
TypeScript Strict - Type Safety Patterns
Purpose
Expert guidance for TypeScript strict mode:
- Strict Null Checks - Handle undefined/null properly
- Index Access - Safe property access patterns
- Literal Types - Const assertions and narrowing
- Generics - Type-safe reusable patterns
- Type Guards - Runtime type validation
Critical tsconfig.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"noPropertyAccessFromIndexSignature": true
}
}
Index Access Patterns
Environment Variables
// WRONG - TS7053
const port = process.env.PORT;
// CORRECT - Use bracket notation
const port = process.env['PORT'];
const host = process.env['HOST'] ?? 'localhost';
Object Property Access
interface Config {
[key: string]: string | undefined;
}
const config: Config = { api: 'https://api.example.com' };
// WRONG - Direct access
const url = config.api;
// CORRECT - Bracket access with check
const url = config['api'];
if (url) {
fetch(url);
}
Array Access
const items = ['a', 'b', 'c'];
// WRONG - Could be undefined
const first = items[0].toUpperCase();
// CORRECT - Check first
const first = items[0];
if (first) {
console.log(first.toUpperCase());
}
// Or use non-null assertion if certain
const guaranteed = items[0]!;
Literal Types & Const Assertions
String Literals
// WRONG - Type is string
const status = 'pending';
// CORRECT - Literal type
const status = 'pending' as const;
// type: "pending"
// Object with literals
const config = {
mode: 'production' as const,
level: 'high' as const,
};
Object Literals
// WRONG - Types are widened
const endpoints = {
users: '/api/users',
posts: '/api/posts',
};
// type: { users: string; posts: string }
// CORRECT - Exact types
const endpoints = {
users: '/api/users',
posts: '/api/posts',
} as const;
// type: { readonly users: "/api/users"; readonly posts: "/api/posts" }
Discriminated Unions
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
return result.data;
} else {
// TypeScript knows result.error exists here
throw new Error(result.error);
}
}
Null & Undefined Handling
Optional Chaining
interface User {
profile?: {
avatar?: string;
};
}
// CORRECT - Optional chaining
const avatar = user.profile?.avatar ?? '/default.png';
Nullish Coalescing
// WRONG - || treats 0, '', false as falsy
const count = input || 10;
// CORRECT - ?? only treats null/undefined as nullish
const count = input ?? 10;
Type Guards
// Custom type guard
function isUser(value: unknown): value is User {
return typeof value === 'object' && value !== null && 'id' in value && 'email' in value;
}
// Usage
function processData(data: unknown) {
if (isUser(data)) {
// TypeScript knows data is User here
console.log(data.email);
}
}
Assertion Functions
function assertDefined<T>(value: T | undefined | null, message: string): asserts value is T {
if (value === undefined || value === null) {
throw new Error(message);
}
}
// Usage
const user = await getUser(id);
assertDefined(user, `User ${id} not found`);
// user is guaranteed to be defined after this
console.log(user.name);
Generic Patterns
Constrained Generics
// Ensure T has an id property
function findById<T extends { id: string }>(items: T[], id: string): T | undefined {
return items.find((item) => item.id === id);
}
// Works with any type that has id
interface User {
id: string;
name: string;
}
interface Post {
id: string;
title: string;
}
findById(users, '123'); // T is User
findById(posts, '456'); // T is Post
Infer Return Type
// Infer return type from callback
function createFetcher<T>(fetcher: () => Promise<T>) {
return {
fetch: fetcher,
refetch: () => fetcher(),
};
}
// T is automatically inferred
const userFetcher = createFetcher(async () => {
const res = await fetch('/api/user');
return res.json() as Promise<User>;
});
// userFetcher.fetch() returns Promise<User>
Mapped Types
// Make all properties optional
type Partial<T> = {
[P in keyof T]?: T[P];
};
// Make all properties readonly
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// Pick specific properties
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
// Custom: Make specific properties required
type RequireFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
Utility Types
// Exclude null/undefined
type NonNullable<T> = T extends null | undefined ? never : T;
// Extract function return type
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
// Extract function parameters
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
// Usage
type UserSchema = z.infer<typeof userSchema>;
type ApiResponse = Awaited<ReturnType<typeof fetchUser>>;
Common Errors & Fixes
TS2532: Object is possibly 'undefined'
// ERROR
const name = user.profile.name;
// FIX - Optional chaining
const name = user.profile?.name ?? 'Unknown';
TS2339: Property does not exist
// ERROR
const env = process.env.NODE_ENV;
// FIX - Bracket access
const env = process.env['NODE_ENV'];
TS7053: Index signature
// ERROR
const value = obj[key];
// FIX - Type assertion or bracket notation
const value = (obj as Record<string, unknown>)[key];
Agent Integration
This skill is used by:
- ts-strict-checker agent
- ts-types-analyzer agent
- type-error-resolver agent
- quality-checker for typecheck validation
Commands
# Type check
bun run typecheck
bunx tsc --noEmit
# Check specific file
bunx tsc --noEmit path/to/file.ts
# Generate types
bunx tsc --declaration --emitDeclarationOnly
FORBIDDEN
anytype - Useunknowninstead- Non-null assertion without certainty - Check first
- Type assertion to hide errors - Fix the actual issue
- Ignoring strict errors - Always fix properly
@ts-ignorewithout explanation - Use@ts-expect-errorwith comment
Version
- v1.0.0 - Initial implementation based on TypeScript 5.x strict patterns
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?