Search code examples
typescripttypescript-declarations

Typescript: emit declarations file with different types from implementation?


Is it possible to instruct the TypeScript compiler to emit declaration files with different typings than the ones used in implementation? For example:

// source brewery.ts
function brewBeer(name: unknown): Beer { ... }

// emitted brewery.d.ts
declare function brewBeer(name: string): Beer;

“Why would you want that?”

I'm writing a library in TypeScript that I expect to be used also in non-TypeScript projects. For this reason, I check at runtime the validity of the parameters passed to the exposed functions, like this:

export function brewBeer(name: string): Beer {
  if (typeof name !== 'string') {
    throw new TypeError(`'${name}' is not a beer name.`);
  }
  // Continue brewing...
}

This approach is usable but not perfect:

  1. I cannot unit test the behavior when incorrect type of parameters are passed because, since the test files are also in TypeScript, tests will not even run when type constraints are not met:

    TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

  2. The compiler, of course, does not enforce validating parameters at compile time.

At first glance both issues could be solved with the unknown top type:

  1. I could pass any type of parameter in my tests to evaluate the runtime behavior.
  2. The compiler helps by enforcing the assertion of the function parameters before cosuming them.

However this approach is also flawed as the emitted declaration would look like this:

// brewery.d.ts
declare function brewBeer(name: unknown): Beer;

which would be of little to no utility in projects that do use TypeScript.

So, is there a way to use unknown and still emit declaration files with the "correct" types without manually correcting them?


Solution

  • Is it possible to instruct the TypeScript compiler to emit declaration files with different typings than the ones used in implementation.

    Simple answer: no.