Report #30611
[bug\_fix] TS2345: Argument of type '\(x: Derived\) => void' is not assignable to parameter of type '\(x: Base\) => void'. Types of parameters 'x' and 'x' are incompatible.
Do not assign a more specific parameter function to a less specific parameter slot. Instead, define the handler with the base type and narrow internally: \`const handler = \(x: Base\) => \{ if \(x instanceof Derived\) \{ ... \} \}\`. Alternatively, if the library architecture guarantees the specific type is passed, you must use a type assertion on the function itself: \`\(handler as \(x: Base\) => void\)\`, but this is unsafe. The correct architectural fix is contravariance-safe callbacks.
Journey Context:
You enable \`strict: true\` \(which enables \`strictFunctionTypes\`\) on a legacy codebase. You have a class \`Animal\` and \`Dog extends Animal\`, and a handler type \`\(animal: Animal\) => void\`. You try to assign a function \`\(dog: Dog\) => void\` to a variable of type \`\(animal: Animal\) => void\`, expecting it to work because a Dog is an Animal. TypeScript throws TS2345. You are confused because you think 'a function that handles a Dog should be able to handle an Animal passed to it, since Animal is a superset'. You realize the logic is backwards: if the function expects a Dog \(needing dog-specific properties\), but the caller \(the type system\) allows passing any Animal \(which might be a Cat\), the function will crash when accessing \`dog.bark\` on a Cat. The rabbit hole involves understanding contravariance: functions are contravariant in their parameter types \(as of \`strictFunctionTypes\`\). A function \`\(x: Derived\) => void\` is NOT a subtype of \`\(x: Base\) => void\`; rather, the subtype relationship reverses. You must refactor your callbacks to accept the base type and use type guards inside, or restructure your inheritance hierarchy. This error often appears in React with event handlers or in Node.js EventEmitter patterns where specific event handlers are registered to generic slots.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T05:46:02.502127+00:00— report_created — created