BuildNot yet confirmed elsewhere1 publisher3 min readPublished
TypeScript 6.0's strict default would turn your callbacks into a variance audit
A dev.to post says strictFunctionTypes goes on by default in TypeScript 6.0. If it does, the upgrade cost is per-declaration, and casting your way out swaps compile errors for crashes.
The Engineer · Build desk
What happened
- A dev.to article states that TypeScript 6.0 enables strict mode by default, that strictFunctionTypes is the compiler flag behind most TypeScript migration failures, and that codebases which never configured contravariance checking will fail to compile overnight.
- The article carries a disclosure that it was written with the assistance of AI, under human supervision and review.
- The breaking pattern described: a callback registered to an array method expects Animal while the implementation passes Dog; pre-6.0 TypeScript allowed this through bivariant parameter checking, and post-6.0 the compiler rejects it as unsafe.
- Method signatures retain bivariant checking for compatibility while function properties enforce contravariance; the choice between foo(x: T): void and foo: (x: T) => void determines variance behaviour.
- Contravariance means a function that accepts a more general parameter type can substitute for one that accepts a more specific type: if a callback expects Dog you can safely pass a function that accepts Animal, but not the reverse.
Why it matters
A post on dev.to argues that TypeScript 6.0 enables strict mode by default, and that the flag most likely to break working code on upgrade is `strictFunctionTypes` [10]. If that holds, a setting you never opted into starts rejecting callbacks that have compiled for years [10], and the remedy is not one line of tsconfig but a review of how each callback was declared [3].
The shape of the break is small and common. A callback registered against an array method declares that it accepts `Animal` while the consumer will call it with `Dog`; pre-6.0 TypeScript allowed that through bivariant parameter checking, and post-6.0 the compiler rejects it as unsafe [2]. The rule being enforced is contravariance: a function accepting a more general parameter type can stand in for one accepting a more specific type, so a slot expecting `Dog` will take a function that accepts `Animal`, but not the reverse [4]. Return types run the other way and are covariant, because a function returning `Dog` can substitute for one returning `Animal` and the caller only ever receives something more specific than it asked for [6].
The compiler cares because the consumer controls the arguments. `Array<Dog>.map` will invoke the callback with `Dog` instances, and if the signature declares `(animal: Animal) => void` then every operation in the body has to be safe for the broader type; the post's example is that accepting a function which expects `Dog` lets `dog.bark()` run against a generic `Animal` and crash at runtime [5].
Here is why this is an audit rather than a flag flip. Variance depends on the syntax you used: a method signature such as `foo(x: T): void` keeps bivariant checking for backward compatibility, while the property form `foo: (x: T) => void` gets contravariant checking [3]. Two declarations that read identically to a human are treated differently by the compiler, so the error count you get from turning the flag on is a symptom, not a measure of the work.
The escape hatches are where the cost gets moved rather than paid. Teams facing hundreds of errors reach for `any` or incorrect casts that introduce runtime bugs, according to the post [11], which lists the legitimate options as widening parameter types to unions, switching to method syntax where bivariance is genuinely intended, or adding generic constraints that preserve assignability without `any` [7]. Note what the method-syntax rewrite actually does: because method signatures retain bivariance, rewriting a function property as a method restores exactly the pre-6.0 acceptance and changes nothing at runtime [8]. A cast does the same trick, keeping the unsound call path and removing the warning about it [9]. The post also argues that disabling `strictFunctionTypes` outright leaves you with a type system that diverges from third-party libraries whose types are built for contravariance [12].
Two things to check before you budget for this. The dev.to post carries a disclosure that it was written with AI assistance under human supervision and review [1], and in the text supplied it asserts the 6.0 default change without pointing to a release note, issue number, or date [13]; confirm the default against TypeScript's own release notes before scheduling work. In the meantime the dry run is cheap: set `strictFunctionTypes` to true on a branch and count what falls over [10]. That number is your exposure whether or not 6.0 ships the default.
Clarity's read
What the record supports and how the coverage leans. The claims behind it follow.
Reality
- Evidence22
- Adoption
- Insufficient
- Hype gap+58
- Incentives
- Insufficient
- Confidence26
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
The article carries a disclosure that it was written with the assistance of AI, under human supervision and review.
- [2]
The breaking pattern described: a callback registered to an array method expects Animal while the implementation passes Dog; pre-6.0 TypeScript allowed this through bivariant parameter checking, and post-6.0 the compiler rejects it as unsafe.
- [3]
Method signatures retain bivariant checking for compatibility while function properties enforce contravariance; the choice between foo(x: T): void and foo: (x: T) => void determines variance behaviour.
- [4]
Contravariance means a function that accepts a more general parameter type can substitute for one that accepts a more specific type: if a callback expects Dog you can safely pass a function that accepts Animal, but not the reverse.
- [5]
Because consumers control the arguments, Array<Dog>.map invokes its callback with Dog instances; if the signature declares (animal: Animal) => void, TypeScript must verify every operation in the body is safe for the broader Animal type, and accepting a function that expects Dog would allow code like dog.bark() to execute on a generic Animal, causing a runtime crash.
- [6]
Return types are covariant because a function returning Dog can substitute for one returning Animal, the caller receiving a more specific type than expected; parameter types are checked in the opposite direction.
- [7]
Listed migration strategies: widening parameter types to unions, using method syntax where bivariance is intentional, or introducing generic constraints that preserve assignability without any.
- [8]
Rewriting a function-property callback declaration as a method signature restores the same bivariant acceptance that existed before 6.0 and changes nothing about runtime behaviour, so it suppresses the diagnostic rather than fixing the unsound assignment.
- [9]
Silencing the error with any or a type assertion leaves the unsafe call path intact, so the compile-time error is exchanged for the runtime failure it was flagging.
- [10]
A dev.to article states that TypeScript 6.0 enables strict mode by default, that strictFunctionTypes is the compiler flag behind most TypeScript migration failures, and that codebases which never configured contravariance checking will fail to compile overnight.
ReportedInsufficientSource: dev.to (jsmanifest)2 sources— create a free account to open themView cited source - [11]
The article says teams scramble to fix hundreds of type errors without understanding the variance rules, often choosing any or incorrect casts that introduce runtime bugs.
ReportedInsufficientSource: dev.to (jsmanifest)2 sources— create a free account to open themView cited source - [12]
The article argues third-party libraries ship types built for contravariance, and that disabling strictFunctionTypes to silence errors creates a type system that diverges from reality, where the compiler promises safety it cannot enforce.
ReportedInsufficientSource: dev.to (jsmanifest)2 sources— create a free account to open themView cited source - [13]
In the supplied text, the article asserts the TypeScript 6.0 default change without citing a release note, issue number, or ship date.
Sources
1 independent publisher whose own reporting we read for this story.
- dev.toTypeScript 6.0 Strict Function Types: Why Contravariance Breaks Your Existing Callbacks
1 article · August 17, 2026
Topics and entities
Follow any of these and your For You feed starts watching them — no settings page required.