Loading...
Loading...
Use when encountering TypeScript any types, type errors, or lax type checking - eliminates type holes and enforces strict type safety through proper interfaces, type guards, and module augmentation
npx skill4agent add pr-pm/prpm typescript-type-safetyanyanyanyunknown@ts-expect-error: anyas anyany.d.tsunknownneverany| Pattern | Bad | Good |
|---|---|---|
| Error handling | | |
| Unknown data | | |
| Type assertions | | |
| Double casting | | Align interfaces instead: make types compatible |
| External libs | | |
| Generics | | |
// ❌ BAD
try {
await operation();
} catch (error: any) {
console.error(error.message);
}
// ✅ GOOD - Use unknown and type guard
try {
await operation();
} catch (error) {
if (error instanceof Error) {
console.error(error.message);
} else {
console.error('Unknown error:', String(error));
}
}
// ✅ BETTER - Helper function
function toError(error: unknown): Error {
if (error instanceof Error) return error;
return new Error(String(error));
}
try {
await operation();
} catch (error) {
const err = toError(error);
console.error(err.message);
}// ❌ BAD
const data = await response.json() as any;
console.log(data.user.name);
// ✅ GOOD - Type guard
interface UserResponse {
user: {
name: string;
email: string;
};
}
function isUserResponse(data: unknown): data is UserResponse {
return (
typeof data === 'object' &&
data !== null &&
'user' in data &&
typeof data.user === 'object' &&
data.user !== null &&
'name' in data.user &&
typeof data.user.name === 'string'
);
}
const data = await response.json();
if (isUserResponse(data)) {
console.log(data.user.name); // Type-safe
}// ❌ BAD
const user = (request as any).user;
const db = (server as any).pg;
// ✅ GOOD - Augment third-party types
import { FastifyRequest, FastifyInstance } from 'fastify';
interface AuthUser {
user_id: string;
username: string;
email: string;
}
declare module 'fastify' {
interface FastifyRequest {
user?: AuthUser;
}
interface FastifyInstance {
pg: PostgresPlugin;
}
}
// Now type-safe everywhere
const user = request.user; // AuthUser | undefined
const db = server.pg; // PostgresPlugin// ❌ BAD
function merge(a: any, b: any): any {
return { ...a, ...b };
}
// ✅ GOOD - Constrained generic
function merge<
T extends Record<string, unknown>,
U extends Record<string, unknown>
>(a: T, b: U): T & U {
return { ...a, ...b };
}// ❌ BAD - Double cast indicates misaligned types
interface SearchPackage {
id: string;
type: string; // Too loose
}
interface RegistryPackage {
id: string;
type: PackageType; // Specific enum
}
return data.packages as unknown as RegistryPackage[]; // Hiding incompatibility
// ✅ GOOD - Align types from the source
interface SearchPackage {
id: string;
type: PackageType; // Use same specific type
}
interface RegistryPackage {
id: string;
type: PackageType; // Now compatible
}
return data.packages; // No cast needed - types matchas unknown as Type.js.ts.js// ❌ BAD - Will fail at runtime in ESM
import { helper } from './utils';
import { CLIError } from '../utils/cli-error';
import type { Package } from './types/package';
// ✅ GOOD - Explicit .js extensions
import { helper } from './utils.js';
import { CLIError } from '../utils/cli-error.js';
import type { Package } from './types/package.js';ERR_MODULE_NOT_FOUND{
"compilerOptions": {
"module": "NodeNext",
"moduleResolution": "NodeNext",
// OR
"module": "ESNext",
"moduleResolution": "bundler"
}
}| Pattern | Issue | Fix |
|---|---|---|
| Missing extension | |
| Missing index | |
| Package export | Check package.json |
# Find imports missing .js extension
grep -rn "from '\.\.\?/[^']*[^j][^s]'" --include="*.ts" src/
# ESLint rule (if using eslint)
# "import/extensions": ["error", "always", { "ignorePackages": true }]| Mistake | Why It Fails | Fix |
|---|---|---|
Using | Loses all type safety | Use module augmentation or |
| Hides real type errors | Create proper interface or use |
| Misaligned interfaces | Align types at source - same enums/unions |
| Skipping catch block types | Unsafe error access | Use |
| Generic functions without constraints | Allows invalid operations | Add |
Ignoring | Tech debt compounds | Fix root cause, use |
Missing | ESM runtime failures | Always use |
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}grep -r ": any\|as any" --include="*.ts" src/npm run buildany