-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Declaration emit reveals paths within dependency that were not referred to in the source file #38111
Comments
When writing up that issue we also found out a pretty interesting effect. If you were to move the
import { TheInterface } from "./int/internal-types";
export { TheInterface };
export declare function getInstance(): TheInterface; We do get the wanted declaration output:
export declare const instance: import("dependency/entrypoint").TheInterface; This is great because that means that TypeScript has a notion of some files are meant to be imported and others do not.
function sortByBestName(a: number, b: number) {
const specifierA = parentSpecifiers[a];
const specifierB = parentSpecifiers[b];
if (specifierA && specifierB) {
const isBRelative = pathIsRelative(specifierB);
if (pathIsRelative(specifierA) === isBRelative) {
// Both relative or both non-relative, sort by number of parts
return moduleSpecifiers.countPathComponents(specifierA) - moduleSpecifiers.countPathComponents(specifierB);
}
if (isBRelative) {
// A is non-relative, B is relative: prefer A
return -1;
}
// A is relative, B is non-relative: prefer B
return 1;
}
return 0;
} #27340 / 7a71887 by @weswigham Is that behavior intentional, in which case we can use it as a workaround, or is this arbitrary behavior that can change? |
Additionally the example here leverages |
Preferring he shortest (in path segments) absolute path we find is intended behavior, yes. |
@weswigham thanks for getting back to us. Is the "prefer the shortest (in path segments) path" behavior that is likely to not change in future releases? If so, we can use it to hack around the problem we're seeing:
Ideally, there would be a non-hacky userspace solution, but the subdirectorification trick could work in the short term. |
It is the only heuristic we currently use to sort all found import paths. The only other heuristic I could see us maybe using in the future is combining it with a "longest alias chain to source" (minus cycles) to break ties, but calculating that would be crazy expensive compared to just this (which is essentially a string comparison and loosely tracks the same thing in conventional project structures). Since we have no interest in making the already sluggish declaration emit slower, we're unlikely to change it anytime soon, I think. And even then, we'd still be using segment count as the initial sort and filter, so if you were relying on it, you'd be fine. |
@weswigham One additional heuristic that might help solve this problem in future would be to favour explicit package entrypoints as designated in pkg.json That would ensure generated declaration files use the same encapsulation boundaries defined by the source code's modules & packages. |
When we add support for the new esm and cjs resolvers in node, yeah, probably. |
For the record, we solved this problem by making our build tool inject ambient module declarations for each external dependency into a generated file we call // ambient.d.ts
declare module "my-dependency" {
export * from "../../../path/to/dependency";
} Ambient module declarations and tsconfig Maybe we should update the documentation for |
@robpalme Could you setup a complete example? When I try it with declare module '@material-ui/core' {
export * from './packages/material-ui/src/';
} I get How would this work for wildcard paths like |
This has gotten worse with the introduction of |
Context:
Declaration emit reveals paths within dependency that were not referred to in the source file:
This is a problem because changing paths within a dependency can break a dependent package.
TypeScript Version: 3.9.0-dev.20200212
Search Terms:
Code
node_modules/@types/dependency/entrypoint.d.ts
node_modules/@types/dependency/internal-types.d.ts
node_modules/@types/dependency/index.d.ts
example.ts
src/app/tsconfig.json
Expected behavior:
example.d.ts
Actual behavior:
example.d.ts
It seems that part of the solution could involve having the compiler avoid using relative paths in types (
import("<relativepath>").<typename>
) if therelativepath
is outside the project.Repro Repo: https://github.com/mheiber/repro-rel-import-inlining
Related Issues:
Issue written with the help of: @rricard, @robpalme and @mkubilayk
The text was updated successfully, but these errors were encountered: