[typescript] About "*.d.ts" in TypeScript

I'm feeling curious about *.d.ts because I'm a newbie in TypeScript. And I was told by someone that this kind of file is something like "head file" in C++ but for JS only. But I cannot convert a pure JS file to *.d.ts file unless I forcely change the *.js to *.ts. So I have three files: a JS file, a TS file and a *.d.ts file.


  1. What's the relationship between them?

  2. How can I use the *.d.ts file? Does it mean I can delete the *.ts file permanently?

  3. If so, how can the *.d.ts file know which JS file is mapping to itself?


It would be very nice if someone can give me an example.

This question is related to typescript .d.ts

The answer is


The "d.ts" file is used to provide typescript type information about an API that's written in JavaScript. The idea is that you're using something like jQuery or underscore, an existing javascript library. You want to consume those from your typescript code.

Rather than rewriting jquery or underscore or whatever in typescript, you can instead write the d.ts file, which contains only the type annotations. Then from your typescript code you get the typescript benefits of static type checking while still using a pure JS library.


I could not comment and thus am adding this as an answer.
We had some pain trying to map existing types to a javascript library.

To map a .d.ts file to its javascript file you need to give the .d.ts file the same name as the javascript file, keep them in the same folder, and point the code that needs it to the .d.ts file.

eg: test.js and test.d.ts are in the testdir/ folder, then you import it like this in a react component:

import * as Test from "./testdir/test";

The .d.ts file was exported as a namespace like this:

export as namespace Test;

export interface TestInterface1{}
export class TestClass1{}

Like @takeshin said .d stands for declaration file for typescript (.ts).

Few points to be clarified before proceeding to answer this post -

  1. Typescript is syntactic superset of javascript.
  2. Typescript doesn't run on its own, it needs to be transpiled into javascript (typescript to javascript conversion)
  3. "Type definition" and "Type checking" are major add-on functionalities that typescript provides over javascript. (check difference between type script and javascript)

If you are thinking if typescript is just syntactic superset, what benefits does it offer - https://basarat.gitbooks.io/typescript/docs/why-typescript.html#the-typescript-type-system

To Answer this post -

As we discussed, typescript is superset of javascript and needs to be transpiled into javascript. So if a library or third party code is written in typescript, it eventually gets converted to javascript which can be used by javascript project but vice versa does not hold true.

For ex -

If you install javascript library -

npm install --save mylib

and try importing it in typescript code -

import * from "mylib";

you will get error.

"Cannot find module 'mylib'."

As mentioned by @Chris, many libraries like underscore, Jquery are already written in javascript. Rather than re-writing those libraries for typescript projects, an alternate solution was needed.

In order to do this, you can provide type declaration file in javascript library named as *.d.ts, like in above case mylib.d.ts. Declaration file only provides type declarations of functions and variables defined in respective javascript file.

Now when you try -

import * from "mylib";

mylib.d.ts gets imported which acts as an interface between javascript library code and typescript project.


Worked example for a specific case:

Let's say you have my-module that you're sharing via npm.

You install it with npm install my-module

You use it thus:

import * as lol from 'my-module';

const a = lol('abc', 'def');

The module's logic is all in index.js:

module.exports = function(firstString, secondString) {

  // your code

  return result
}

To add typings, create a file index.d.ts:

declare module 'my-module' {
  export default function anyName(arg1: string, arg2: string): MyResponse;
}

interface MyResponse {
  something: number;
  anything: number;
}

d stands for Declaration Files:

When a TypeScript script gets compiled there is an option to generate a declaration file (with the extension .d.ts) that functions as an interface to the components in the compiled JavaScript. In the process the compiler strips away all function and method bodies and preserves only the signatures of the types that are exported. The resulting declaration file can then be used to describe the exported virtual TypeScript types of a JavaScript library or module when a third-party developer consumes it from TypeScript.

The concept of declaration files is analogous to the concept of header file found in C/C++.

declare module arithmetics {
    add(left: number, right: number): number;
    subtract(left: number, right: number): number;
    multiply(left: number, right: number): number;
    divide(left: number, right: number): number;
}

Type declaration files can be written by hand for existing JavaScript libraries, as has been done for jQuery and Node.js.

Large collections of declaration files for popular JavaScript libraries are hosted on GitHub in DefinitelyTyped and the Typings Registry. A command-line utility called typings is provided to help search and install declaration files from the repositories.


This answer assumes you have some JavaScript that you don't want to convert to TypeScript, but you want to benefit from type checking with minimal changes to your .js. A .d.ts file is very much like a C or C++ header file. Its purpose is to define an interface. Here is an example:

mashString.d.ts

/** Makes a string harder to read. */
declare function mashString(
    /** The string to obscure */
    str: string
):string;
export = mashString;

mashString.js

// @ts-check
/** @type {import("./mashString")} */
module.exports = (str) => [...str].reverse().join("");

main.js

// @ts-check
const mashString = require("./mashString");
console.log(mashString("12345"));

The relationship here is: mashString.d.ts defines an interface, mashString.js implements the interface and main.js uses the interface.

To get the type checking to work you add // @ts-check to your .js files. But this only checks that main.js uses the interface correctly. To also ensure that mashString.js implements it correctly we add /** @type {import("./mashString")} */ before the export.

You can create your initial .d.ts files using tsc -allowJs main.js -d then edit them as required manually to improve the type checking and documentation.

In most cases the implementation and interface have the same name, here mashString. But you can have alternative implementations. For example we could rename mashString.js to reverse.js and have an alternative encryptString.js.