JavaScript is not a statically typed language. TypeScript gives you the illusion that there are types during development but once it's compiled into JavaScript, all that disappears. that's why you need libraries like Zod for runtime type checking.
When you want to share the library/package you've written in TypeScript with others, you need to generate and include a separate type declaration file (ending in .d.ts
) so other developers can access your type definitions during development. (You also need to add a "types"
entry in "package.json"
pointing to that file)
1. Limitations of tsconfig.json
In the tsconfig.json
file that is generated after running the tsc --init
command (it comes by default in many libraries like Vite.js), there are options you can enable to generate declaration files like "declaration"
, "declarationDir"
, etc.
But you will run into limitations and problems if you just use the options available in this file, like:
- Not being able to generate declaration files for only specific files
The "include"
option is for including the files in your whole project not just type declaration generation. so if you exclude other files (set it to only the files you need declarations for), those files won't be seen by typescript at all and you will get lots of errors.
- Not being able to rename/modify the generated declaration files
When your project grows, you may want to separate your type definitions into another file like types/types.ts
and import it in your main file. but when building/shipping, you want all of your types to be in a index.d.ts
file in the root of your dist
folder. you can't achieve that with tsconfig.json
2. vite-plugin-dts to the rescue
There is a plugin called vite-plugin-dts
for Vite.js which makes generating declaration files much easier.
- Installation
You can install it by running this command:
npm i vite-plugin-dts -D
Then in your vite.config.ts
file add these lines:
import dts from 'vite-plugin-dts';
// add dts() to the plugins array
plugins: [react(), dts()],
- Generating declarations for specific files
By default, declaration files will be generated for all files but you can limit it to specific files by using the include
option:
dts({
include: ['path/to/file.ts'],
}),
- Renaming/Modifying the generated declaration files
You can rename the generated files to something else or even modify the content by using the beforeWriteFile
option. you can pass a function that takes two arguments (filePath: string, content: string)
and returns an object with the same-name properties {filepath: 'new/path/to/file.d.ts', content: 'newContent'}
. if you return false
the file will be skipped.
dts({
beforeWriteFile: (filePath, content) => ({
filePath: filePath.replace('path/to/file.d.ts', 'index.d.ts'),
content,
}),
}),
- Changing the output directory
you can use the outDir
option to limit declaration file generation to specific directories. (you can achieve this using the options in tsconfig.json
as well)
dts({
outDir: 'dist',
}),
There are many more options available that you can check in the documentation
The build process in JavaScript/TypeScript can be confusing with all of the different tools and options available. hopefully, this article can help with making it a little easier.
Top comments (2)
Thank you!
Watch out for this underlying vulnerability that
vite-plugin-dts
has - github.com/qmhc/vite-plugin-dts/is...