Loading...
Loading...
Use when any is unavoidable. Use when working with untyped libraries. Use when silencing specific type errors.
npx skill4agent add marius-townhouse/effective-typescript-skills narrow-any-scopeNEVER let any escape its minimal necessary scope.// ❌ VIOLATION: any on parameter escapes to return value
function processExpression(expression: any) {
const result = expression.evaluate(); // result is any
return result; // Returns any - spreads everywhere
}
// ✅ BETTER: any only where needed
function processExpression(expression: any) {
const result: number = expression.evaluate(); // Constrain immediately
return result; // Returns number
}// ❌ BAD: any spreads
const config = getConfig() as any;
config.debug = true; // config stays any
const debug = config.debug; // debug is any
// ✅ GOOD: Constrain immediately
const config = getConfig() as any;
const debug: boolean = config.debug; // debug is boolean// ❌ BAD: any on the whole object
function processObject(obj: any) {
obj.x = 1;
obj.y = 2;
return obj; // Returns any
}
// ✅ GOOD: any only on the problematic line
function processObject(obj: Foo) {
// @ts-expect-error - The library typings are wrong here
(obj as any).secretMethod();
return obj; // Returns Foo
}// ❌ BAD: Return type infected by any
function parse(input: string) {
const parsed = JSON.parse(input); // parsed is any
return parsed; // Return type is any
}
// ✅ GOOD: Explicit return type blocks the any
function parse(input: string): ParsedData {
const parsed = JSON.parse(input); // Still any internally
return parsed; // But return type is ParsedData
}// ❌ BAD: any infects the whole expression
function calculate(a: number, b: any, c: number) {
return a + b + c; // Result is any because b is any
}
// ✅ BETTER: Convert any before use
function calculate(a: number, b: any, c: number) {
const bNum: number = b; // Constrain b to number
return a + bNum + c; // Result is number
}// ❌ BAD: Changing parameter type to any
function processUser(user: any) {
return user.name.toUpperCase();
}
// ✅ GOOD: Keep the type, assert where needed
function processUser(user: User) {
// Only use any assertion if absolutely necessary
return (user as any).secretField; // any is inline only
}// ❌ DANGEROUS: any[] elements are any
function getFirst(arr: any[]) {
return arr[0]; // Returns any
}
// ✅ SAFER: Use generics or unknown
function getFirst<T>(arr: T[]): T {
return arr[0]; // Returns T
}
function getFirst(arr: unknown[]): unknown {
return arr[0]; // Returns unknown - forces checking
}// ❌ BAD: Maximally broad any
type Callback = any;
// ✅ BETTER: Precise function types
type Callback0 = () => any; // No params
type Callback1 = (arg: any) => any; // One param
type CallbackN = (...args: any[]) => any; // Any params| Excuse | Reality |
|---|---|
| "It's contained" | any spreads through returns and assignments. |
| "Only used once" | That's one bug waiting to happen. |
| "I'll fix it later" | Later never comes. Scope it now. |
| "The function is short" | Short functions can still spread any. |
| any Situation | Narrowing Technique |
|---|---|
| any parameter | Add return type annotation |
| any return value | Add explicit return type |
| any in expression | Assign to typed variable |
| any from JSON.parse | Add return type or validate |
| any from library | Assert to specific type |
// Before: any everywhere
function process(data: any): any {
const x = data.foo; // any
const y = data.bar; // any
return { x, y }; // any
}
// After: any contained
function process(data: any): Result {
const x: number = data.foo; // number
const y: string = data.bar; // string
return { x, y }; // Result
}