When maintaining a library with a peer dependency that supports multiple major versions of a library, can we make Typescript account for the known breaking changes, by treating imports as a union of the types of the latest in each supported major version, instead of treating them as just the single latest version in the range?
For example, imagine a library, foo
, where [email protected]
exported:
{
bar: { baz: () => void, ... },
fuzz: () => void,
...
}
...and [email protected]
had a breaking change where it moved "fuzz" to a method of "baz", like:
{
bar: { baz: () => void, fuzz: () => void, ... },
...
}
We're authoring a library where we use foo.bar.baz()
and we don't currently use fuzz
. We import foo as a peer dependency, and support both versions:
"peerDependencies": {
"foo": "^1.0.0 || ^2.0.0"
Suppose a colleague then decided to use fuzz
, and called bar.fuzz()
in a file with import { bar } from 'foo'
. Typescript would see the installed version of foo
, see that bar
has a method fuzz
, and there would be no type errors, but there will be a runtime error for any consumer using the supported older version [email protected].
Can we configure Typescript so that when we import { bar } from 'foo'
, the type of bar
reflects the reality that it might be either of the two different types in the latest versions of the two supported major versions of the peer dependency, so that it will catch errors for supported legacy versions?
I don't need to account for differences between minor or patch versions, I think it's reasonable to expect a consumer to be using the latest minor or patch within our peer range, but I do want Typescript to account for the known supported breaking changes between major versions of a peer dependency, so that we get type errors if we break our intentional legacy support.