Designs complex generic types, refactors `any` types to strict alternatives, creates type guards and utility types, and resolves TypeScript compiler errors. Use when the user asks about TypeScript (TS) types, generics, type inference, type guards, removing `any` types, strict typing, type errors, `infer`, `extends`, conditional types, mapped types, template literal types, branded/opaque types, or utility types like `Partial`, `Record`, `ReturnType`, and `Awaited`.
97
97%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
TypeScript errors can be cryptic, especially with complex generic types. This guide provides strategies for understanding and resolving type errors effectively.
TypeScript writes errors top-down, but the actual cause is usually at the bottom:
Type '{ name: string; }' is not assignable to type 'User'.
Types of property 'email' are incompatible.
Type 'undefined' is not assignable to type 'string'.
^^^^^^
The actual issue!Use IDE hover tooltips extensively:
const result = someFunction(arg);
// ^ Hover here to see the inferred typeNavigate to type definitions to understand what's expected:
document.querySelector("body");
// ^ Go-to-definition to see overloadsExtract parts of complex types to understand them:
// Complex expression
type Result = SomeComplexType<Input>[keyof Input][number];
// Break it down
type Step1 = SomeComplexType<Input>;
type Step2 = Step1[keyof Input];
type Step3 = Step2[number];The most common error. Check:
// Example: Literal type mismatch
const status = "active"; // Type: string (widened)
function setStatus(s: "active" | "inactive") {}
setStatus(status); // Error!
// Fix: Use as const
const status = "active" as const; // Type: "active"
setStatus(status); // OKThe type doesn't have the expected property:
// Check 1: Is the type correct?
function process(data: unknown) {
data.name; // Error: 'name' doesn't exist on 'unknown'
}
// Fix: Add type guard
function process(data: unknown) {
if (typeof data === "object" && data !== null && "name" in data) {
data.name; // OK
}
}You're trying to access a property that might not exist:
function getValue<T>(obj: T, key: string) {
return obj[key]; // Error: string can't index T
}
// Fix: Constrain the key
function getValue<T, K extends keyof T>(obj: T, key: K) {
return obj[key]; // OK
}Function argument type mismatch:
// Often happens with narrower function signatures
const items = ["a", "b", "c"] as const;
items.includes(someString);
// Error: 'string' not assignable to '"a" | "b" | "c"'
// Fix: Cast appropriately
(items as readonly string[]).includes(someString);Trying to pass type arguments to a non-generic type:
type NotGeneric = string;
type Attempt = NotGeneric<number>; // Error!
// Check if you need to add a generic parameter
type IsGeneric<T> = T;
type Works = IsGeneric<number>; // OKfunction process<T>(items: Parameters<T>) {}
// Error: 'T' does not satisfy constraint '(...args: any) => any'
// Fix: Add the constraint
function process<T extends (...args: any) => any>(items: Parameters<T>) {}Remove complexity until the error is clear:
// Complex chain causing error
const result = complexFunction()
.map(transform)
.filter(predicate)
.reduce(accumulator);
// Simplify to isolate
const step1 = complexFunction();
// Check: Is step1 what you expect?
const step2 = step1.map(transform);
// Check: Is step2 what you expect?
// Continue until you find the issueForce TypeScript to tell you what's wrong:
// Before: Error somewhere in here
const result = getData().process();
// After: Explicit annotations reveal issues
const data: ExpectedDataType = getData(); // Error if getData returns wrong type
const result: ExpectedResultType = data.process(); // Error if process returns wrong type// @ts-expect-error to Confirm Understanding// If you think this should error:
// @ts-expect-error - string is not assignable to number
const x: number = "hello";
// If the @ts-expect-error is unused, TypeScript will tell you
// meaning the code is actually validFor library types, check the actual definitions:
// In lib.dom.d.ts
interface Document {
querySelector<K extends keyof HTMLElementTagNameMap>(
selectors: K
): HTMLElementTagNameMap[K] | null;
querySelector(selectors: string): Element | null;
}Long errors often have one core problem:
Type '{ fullName: string; id: string; firstName: string; lastName: string; age: number; }'
is not assignable to type
'{ fullName: string; id: string; firstName: string; lastName: string; age: number; agePlus10: number }'.
Property 'agePlus10' is missing in type
'{ fullName: string; id: string; firstName: string; lastName: string; age: number; }'
but required in type '{ fullName: string; agePlus10: number; }'.
^^^^^^^^^
The actual issue!Create type aliases to understand the comparison:
type Actual = typeof problematicValue;
type Expected = ExpectedType;
// Now hover these to comparenode_modules/@types/[library]node_modules/[library]/dist/*.d.tsLook for (+N overload) in tooltips:
document.addEventListener("click", handler);
// ^ Shows (+1 overload)
// Go-to-definition to see all overloads
// The first matching overload is usedSometimes library types are wrong or incomplete:
// When you know better than TypeScript
const element = document.getElementById("root") as HTMLDivElement;// Extend existing types
declare module "some-library" {
interface SomeType {
missingProperty: string;
}
}{
"compilerOptions": {
"strict": true
}
}anyEvery any is a potential type hole:
// Instead of
const data: any = fetchData();
// Use
const data: unknown = fetchData();
// Then narrow with type guards// Instead of any in generics
function wrap<T = any>(value: T) {}
// Constrain appropriately
function wrap<T extends object>(value: T) {}// Think about what could be passed
function process(input: string | string[]) {
// What if input is empty string?
// What if input is empty array?
// What if input has special characters?
}