Skip to content
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

tsconfig paths break when consuming the compiled declaration files from a different package #18972

Closed
scamden opened this issue Oct 5, 2017 · 16 comments
Labels
Duplicate An existing issue was already created

Comments

@scamden
Copy link

scamden commented Oct 5, 2017

TypeScript Version: tried 2.2.1 and 2.5.2

Code

src/file1.ts

export type myType = {anything : number};

src/file2.ts

import { myType } from '@src/file1';

export type myOtherType = {anythingElse : number} & myType;

tsconfig.json

{
  "compilerOptions": {
    "outDir": "./dist",
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "declaration": true,
    "noImplicitAny": true,
    "removeComments": true,
    "sourceMap": true,
    "strictNullChecks": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "noUnusedParameters": true,
    "noUnusedLocals": true,
    "baseUrl": ".",
    "paths": {
      "@src/*": ["./src/*"]
    },
    "lib": ["es2017", "dom"]
  },
  "compileOnSave": false,
  "include": [
    "src/**/*",
    "app/**/*"
  ],
  "exclude": [
    "node_modules",
    "dist"
  ]
}

Expected behavior:
i should be able to import myOtherType in a different package (after say publishing this to npm, with the typings field set to dist/file2.d.ts) without errors

Actual behavior:
typescript says Cannot find module "@src/file1" when compiling any package that consumes these types.

Note: the runtime behavior works properly in my case because i'm handling the module resolution through webpack. It's only the types that are failing and I'm curious how the paths property could be expected to work outside of the package in which they are defined. Is that property simply not meant to be used in a library style package that's being written for external consumption?

@mhegazy
Copy link
Contributor

mhegazy commented Oct 5, 2017

The compiler does not re-write your module names for you. they are considered resource identifiers that should not be messed up with. The configuration in the config file tells the compiler where to find the module, not what the module output name should be.

Please see similar discussions in #18951 and #16640.

@mhegazy mhegazy added the Duplicate An existing issue was already created label Oct 5, 2017
@scamden
Copy link
Author

scamden commented Oct 5, 2017

I did review those issues actually. I've been scouring the internet to understand this. In those issues the concern was about the module names in the actual runtime js. My issue was with the type files themselves so I thought it may be different because otherwise I'm not sure how using paths could ever be valid in declaration files (aka when used in conjunction with declaration : true).

What I'm failing to understand is how the usage of paths in a module that is meant for consumption could ever be valid? Like is this feature meant only to be used in an app style module that would never be consumed? Or is the expectation that I would manually rewrite the module names? and if so why even use paths?

This feature is frequently cited in articles around the web as the typescript corollary for webpack aliases and it works well for that in an app, but is it not meant to be used that way in library? just trying to understand how this config option can work

@mhegazy
Copy link
Contributor

mhegazy commented Oct 5, 2017

In those issues the concern was about the module names in the actual runtime js. My issue was with the type files themselves

The compiler has one view of a module, and it does not make much sense to have the .js an .d.ts have different identities.

so I thought it may be different because otherwise I'm not sure how using paths could ever be valid in declaration files (aka when used in conjunction with declaration : true).

The whole path mapping configuration is about telling the compiler where files will be at runtime. It is not a feature to shorten your file names, so tha tyour write ~\mod instead of ..\..\..\mod.
The place to use path mapping is if you have a post-build script that will move your modules around, and will change their names. this is common for requirejs users. for these use cases, i would expect you apply the same transformation to the .d.ts as you do to the .js files.

This feature is frequently cited in articles around the web as the typescript corollary for webpack aliases and it works well for that in an app, but is it not meant to be used that way in library? just trying to understand how this config option can work

I am not familiar with the webpack resources you mention, so can not comment on them. but again, if nothing is going to move the modules to match the path mappings in the tsconfig.json, consuming the .d.ts with the mapped name will not work.

@DanielRosenwasser
Copy link
Member

I am not familiar with the webpack resources you mention,

To fill in the gap: Webpack has the resolve field to say "an import of this form should be resolved specially to XYZ". TypeScript's path mapping functionality is available so users can model that type of behavior specifically.

@scamden
Copy link
Author

scamden commented Oct 5, 2017

@DanielRosenwasser that's exactly what i'm referring to and in the case of webpack these aliases are persisted into the bundle that gets published for consumption, but that doesn't seem to be true for the matching types that use paths

@scamden
Copy link
Author

scamden commented Oct 5, 2017

@mhegazy ok thanks for the info. I had a suspicion that folks were slightly abusing this feature to make it look a bit like webpack aliases (although daniel's comment above makes me wonder if it isn't still meant to fill that need partially).

so not to waste your time too much further but the official recommendation for importing local modules is to always use relative paths if the module is going to be published? and just suss out how many ../'s you need?

@mhegazy
Copy link
Contributor

mhegazy commented Oct 5, 2017

the official recommendation for importing local modules is to always use relative paths if the module is going to be published? and just suss out how many ../s you need?

yes. that would be my recommendation.

@scamden
Copy link
Author

scamden commented Oct 5, 2017

@DanielRosenwasser just cause you sparked my hope slightly, would it be worth considering proposals to push the paths feature over the line to make it fully match webpack's resolve.alias functionality? (aka make it usable in libraries and not just non-reusable apps)

@jsamr
Copy link

jsamr commented Oct 6, 2017

@mhegazy I understand the reasoning behind, but from a developer perspective, this is really not convenient.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 6, 2017

@mhegazy I understand the reasoning behind, but from a developer perspective, this is really not convenient.

This is what "paths" and "baseUrl" feature addresses. seems like you are looking for a different feature.

@scamden
Copy link
Author

scamden commented Oct 6, 2017

@mhegazy what would be the proper approach to solicit that feature?

@mhegazy
Copy link
Contributor

mhegazy commented Oct 6, 2017

We have had a few issues around that, but nothing clearly asking for a rewrite of module names. feel free to create a new suggestion for it.

@chmln
Copy link

chmln commented Oct 12, 2017

Hello,

Chiming in as the author of https://github.com/chmln/flatpickr, typescript declarations have been my most painful interaction with the language.
Consider this basic usecase of typings.

index.d.ts

import { FlatpickrFn } from "./src/types/instance";
export { Instance } from "./src/types/instance";
export { Options, Plugin } from "./src/types/options";

declare var flatpickr: FlatpickrFn;

export default flatpickr;

The tsc complains about flatpickr/flatpickr#1054 (comment)

TLDR:

the files references contain imports which rely on the baseUrl feature.
These imports are not resolved correctly when they're installed as a part of an npm package. Even if I include the tsconfig.json file inside the package.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 14, 2017

@chmln, for this example, baseUrl is not relevant, it is only relevant if you have non-relative module names, i.e. types/options. I am not sure i quite understand the issue.

The issue i usually see ppl run into, is they use baseUrl and paths as a convince tool to shorten module names in import. this is an incorrect usage of this feature; the compiler does nothing to make the path mapping work at runtime, nor does it do anything in the generated .d.ts files.
only use paths or baseurl if you have a post-build script to move files and/or a runtime loader (e.g. requirejs) that will look up modules with their mapped names at runtime.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 30, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@zerkalica
Copy link

May be this helps. I wrote hacky ts-transform-paths, which rewrites aliased import paths accordingly tsconfig baseUrl and paths in d.ts files too.

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

6 participants