I’m working on a Node.js library and I’ve defined some custom namespaces and interfaces in a .d.ts file that I use as types in my function signatures. However, I’m having trouble getting these types taken into account in my compiled library.
Here’s a minimal example. Our directory structure will be as follows:
test
├── package-lock.json
├── package.json
├── test.ts
├── tsconfig.json
├── dist
│ ├── index.d.ts
│ └── index.js
└── lib
├── index.ts
└── types.d.ts
Here are the contents of the files:
package.json
{
"name": "test",
"version": "1.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"author": "",
"license": "ISC",
"description": ""
}
tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"declaration": true,
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
"include": ["lib/**/*"]
}
lib/types.d.ts
declare namespace MyTypes {
interface Bar {
a: string;
}
interface SecondBar {
a: number;
}
}
lib/index.ts
function foo(bar: MyTypes.Bar): string;
function foo(bar: MyTypes.SecondBar): number;
function foo(bar: MyTypes.Bar | MyTypes.SecondBar): number | string {
if (typeof bar.a === "string") {
return "0";
}
return 1;
}
const MyModule = { foo };
export default MyModule;
Thus, our module will export a function that will have two different return value types depending on the type of its single argument.
The problem here is that when we use TypeScript to compile the library, the type declaration file is not included in the result, so the MyTypes namespace is marked as not found in the function type declaration once TypeScript has compiled it.
So, if we try the library: (file test.ts)
import MyModule from "./dist";
const result = MyModule.foo({ a: "string" })
// result will be a string but will be considered by TypeScript as a number
Thus, result will be considered to have the wrong type, since the MyTypes namespace is purely ignored in compiled files.