-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Description
Bug Report
🔎 Search Terms
- incompatible type
🕗 Version & Regression Information
This bug pertains to the new support for Node16 package exports.
- This is an unexpected compilation error.
- This occurs in TypeScript 4.7.3.
- I was unable to test this on prior versions because it pertains to a feature introduced in 4.7.
⏯ Playground Link
A playground link will not demonstrate the issue because it only occurs when importing a second package's exports.
💻 Code
This PR demonstrates a set of code changes to the @microsoft/fast-element library which results in a package that cannot be properly consumed from TypeScript: microsoft/fast#6087
The PR simply moves some code, which was originally part of the default export, and makes it an optional set of functionality exposed only through a special package export via @microsoft/fast-element/binding/two-way.
This is an important scenario for us and a dependency of our upcoming release.
🙁 Actual behavior
As a test, I built the package, which builds fine. Then I created a new project where I could consume the package. Since we haven't published this package yet (or even merged the PR), I made a quick check by simply copying my local version of the package over into the node_modules folder of my test project. I then attempted to import via the path above. There is no problem importing. The problem is that the types between the default export and the special export don't match, according to the compiler. So, if you have a function that takes a certain type as an input, coming from the default export, and then the special export exports an implementor of that interface, you cannot pass the instance to the function. Here is a made up example of what I'm talking about:
@foo/bar index.ts
export interface Task {
run();
}
export function runTask(task: Task) {
task.run();
}@foo/bar cool-tasks.ts
import { Task } from "./index.js";
export const coolTask: Task = {
run() {
// ellided
}
};@foo/bar package.json
"exports": {
".": {
"types": "./dist/index.d.ts",
"production": "./dist/esm/index.js",
"development": "./dist/esm/index.debug.js",
"default": "./dist/esm/index.js"
},
"./cool-tasks": {
"types": "./dist/dts/cool-tasks.d.ts",
"default": "./dist/esm/cool-tasks.js"
}
}Usage in a Project
import { runTask } from "@foo/bar";
import { coolTask } from "@foo/bar/cool-tasks";
runTask(coolTask); // Compiler error!!! Types are incompatible!Note: I have not tried out this exact code, but this is essentially the pattern from our package with the PR linked above. We cannot pass the twoWay BindingConfig const to the bind function that takes an instance BindingConfig. TypeScript thinks that the types are incompatible, even though they are both referencing the same file in the package.
Here is a screenshot of the real code in action:
This exact same consuming code works perfectly if I simply move the twoWay code back into the default export and import it from there. If you examine the PR above, you will see that all we have done is moved the code to its own file and specified a package export.
🙂 Expected behavior
I would expect this to compile without issue.
