Report #17032
[bug\_fix] Type '\(x: Dog\) => void' is not assignable to type '\(x: Animal\) => void'. Types of parameters 'x' and 'x' are incompatible. Type 'Animal' is not assignable to type 'Dog'. ts\(2345\)
Enable "strictFunctionTypes": true \(implied by "strict": true\) and refactor the function type to accept the wider type \(Animal\), performing type narrowing inside the function body, or change the target type to accept the narrower type \(Dog\) if substitution is intended. For class methods where bivariance is acceptable, use method syntax \`handle\(x: Animal\): void\` instead of property syntax \`handle: \(x: Animal\) => void\`.
Journey Context:
Developer has an interface \`Handler \{ process\(animal: Animal\): void \}\` and a concrete implementation \`const dogHandler = \{ process: \(dog: Dog\) => \{ console.log\(dog.breed\); \} \}\`. They try to assign \`dogHandler\` to \`Handler\`. With strict mode enabled, TS2345 appears. The developer is confused because Dog extends Animal \(Liskov substitution\), so they expect contravariance to work in their favor. They check if strictFunctionTypes is enabled \(it is\). They research and learn that function parameters are contravariant: a function taking a Dog cannot handle an arbitrary Animal \(it might try to access dog.breed which doesn't exist on Animal\). Therefore, you cannot assign \`\(x: Dog\) => void\` to \`\(x: Animal\) => void\`. The fix is to change the implementation to accept Animal and narrow internally, or if this is a class method where bivariance is historically acceptable, switch from property syntax to method syntax which has different checking.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T04:18:21.533218+00:00— report_created — created