.d.ts files (in my case with declare module declarations) should be emitted by ts-loader with updated relative import statement paths.
This is useful for packages that extend the functionality of other packages and want to declare appropriate types to reflect that.
.d.ts files are ignored by ts-loader in all of the following cases:
tsconfig.json in the includes array./// <reference path="./types.d.ts" />.import './types.d.ts';. This additionally results in an Error: TypeScript emitted no output for /path/types.d.ts error being logged to the console.tsconfig-paths-webpack-plugin.git clone [email protected]:opl-/ts-loader-dts-repro.git
cd ts-loader-dts-repro
npm run build
You will find that the types.d.ts file was not emitted anywhere in the dist/ directory and that none of the above methods resolve this issue.
I should probably mention that my current workaround is to use a .ts file instead of .d.ts and import that file from the entry point, forcing webpack/ts-loader to process it. However, this (at least according to my understanding of what the role of .d.ts files is) feels more like a hack than an actual solution.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I hate the stale bot so, so much. Just shoving old issues under the rug as if they didn't exist.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Nope. Still relevant. Why are you even using stale bot?
looks like there is code to specifically avoid including .d.ts files in the output https://github.com/TypeStrong/ts-loader/blob/master/src/instances.ts#L695. I am not a contributor here, so I don't have an explanation for why that is.
Sorry I didn't see this issue. A lot going on right now. If someone would like to look into this and raise a prospective PR that would be most appreciated! @appzuka if you should have some time then this is something you could potentially look at?
I've spent some time looking into this issue and here are my thoughts.
My understanding is that this example builds a library module which is then imported by an outer app. The requirement is to include a .d.ts file in the dist directly so that the importing app knows how to use the built library.
The file types.d.ts is needed to build the minimal example. If it is not included then compilation fails because the compiler does not know that extraMethod exists on webpack.Compiler.
My question is whether it is necessary to declare that extraMethod exists to import the library which is built here. The compiler.extraMethod() statement only exists within app.ts. It is never exported to be consumed by the calling app so there would never be any need for that app to know that extraMethod exists.
If I include the following code in app.ts:
export function CallExtra(compiler: webpack.Compiler) {
compiler.extraMethod();
}
Then after building, app.d.ts in dist contains the following:
import webpack from 'webpack';
export declare function CallExtra(compiler: webpack.Compiler): void;
This allows the app which imports the built library to use CallExtra correctly. It does not know about the extraMethod on webpackCompiler but that is OK, because it is not called directly from the outer app.
If you wanted to make the outer app aware of the extraMethod on Compiler you should include the declaration in types.d.ts directly in the outer app. It seems to me that it would be wrong to include that definition in app.d.ts because extraMethod is not defined in the app. The library which declares extraMethod would be the right place to create the d.ts file which contains this declaration.
If you create a file with the implementation of extraMethod called types.ts:
import webpack from 'webpack';
declare module 'webpack' {
interface Compiler {
extraMethod(): void;
}
}
webpack.Compiler.prototype.extraMethod = () => {}
and then you include this as an entry point in webpack.config.js:
entry: {
app: './lib/app.ts',
types: './lib/types.ts'
},
then on building you will get the types.d.ts file in dist as required. This is the workaround given above.
If there is some reason you want to declare this extraMethod when this library is imported, even though the implementation is not contained here, you would want to copy types.d.ts directly to dist. It is correct that ts-loader does not do this because compiling types.d.ts does not cause any javascript to be emitted. A solution is given in the thread below:
It uses a loader which does nothing to copy the file to the output:
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules|\.d\.ts$/
},
{
test: /\.d\.ts$/,
loader: 'ignore-loader'
},
In summary, I believe ts-loader is behaving correctly in this case. It correctly creates an app.d.ts file containing all declarations for functions which are implemented and exported in the built app. It does not include any of the d.ts files which were only necessary to build the app.
If anyone has any thoughts or counterexamples I would be pleased to discuss further.
Reading @appzuka's explanation it does make sense for .d.ts/declaration files to serve the purpose of declaring types to be used for type checking during build and then never emitted. This makes it possible for each package to provide its own types without them getting duplicated by every package that depends on it.
If that's the case it means that the problem is not with ts-loader but rather with TypeScript's documentation not explaining the role of declaration files well enough. I just tried finding any information on their purpose in the TypeScript documentation and was once again unable to find anything other than the guide which tells you how to write declaration files, but nothing about what they actually are.
This means that the "workaround" I mention here is actually the intended way of exporting extensions like that, so I'm closing this issue.
Most helpful comment
Nope. Still relevant. Why are you even using stale bot?