简体   繁体   中英

Auto generate index.d.ts, type definitions, from a typescript module

If I have a TypeScript module saved as my-function.ts as follows :

export function myFunction (param: number): number { return param }

This will be compiled to JavaScript in whichever way and loose its type definitions. I am then able to create a index.d.ts file which declare this module's definitions, but this seems a bit tedious to redefine/redeclare the definitions.

Are there ways to generate the type definitions automatically from the my-function.ts file to a index.d.ts file?

If you compile with the --declaration flag, TypeScript will automatically generate .d.ts files for you.

This mode will require that you certain types are visible so that they can be described in your .d.ts files.

Here's how I managed to solve it:

Creating the infra

  1. Create an new Node package with typescript for the infra.
  2. Inside the new package, make sure to configure a tsconfig.json with declaration:true Doing so will cause typescript to generate definition files which can be consumed by the users of this infra.

My tsconfig.json:

{
"compilerOptions": {
   "target": "es5",
   "module": "commonjs",
   "declaration": true,
   "outDir": "./tsOutputs"
 },
"include": [
  "lib/**/*.ts",
  "index.ts"
],
"exclude": [
  "test/**/*.ts"
]
  }
  1. Create a an "index.ts" file which will export the public API of the infra.

Note: In order to be able to cast & create instances of objects, you need to have two different exports per each entity. Once as type and another as const .

Here's my index.ts:

import {HttpClient as HC} from "./lib/http/http-client";

import {HttpRequest as HReq, HttpResponse as HRes}  from "./lib/http/contracts";

export namespace MyJsInfra

{

export type HttpClient = HC;

   export namespace Entities{
       export type HttpRequest = HReq;
       export const HttpRequest = HReq;

       export type HttpResponse = HRes;
       export const HttpResponse = HRes;
   }
}`

You can read more info on the reasoning behind this dual declaration in here: https://github.com/Microsoft/TypeScript/issues/10058#issuecomment-236458961

  1. After all of the following, when we'll run build we should have the corresponding "*.d.ts" files per each type. Now we have to handle the package.json of the infra, in order to pack all the items.

  2. Inside the package.json make sure to set the types , main to point to the generated index.d.ts & index.js files. In addition, you have to make sure that the "*.d.ts" files are being packaged as part of infra. In my case, I've specified the following pattern in the files property: "tsOutputs/**/*.d.ts"

Here's my package.json:

    {
  "name": "my-js-infra",
  "version": "1.0.0",
  "description": "Infrastructure code.",
  "scripts": {
    "build":"./node_modules/.bin/tsc -p .",
    "prepublish":"npm run build",
  },

 "homepage": "https://github.com/Nadav/My.JS.Infra#readme",
  "devDependencies": {
   ...
    "typescript": "^2.4.2",
   ...
  },
  "dependencies": {
     ...
    "needle": "^1.4.2",
     ...
  },
  "files": [
    "tsOutputs/**/*.js",
    "tsOutputs/**/*.d.ts",
    "tsOutputs/index.d.ts"
  ],
  "types":"tsOutputs/index.d.ts",
  "main":"tsOutputs/index.js"
}

All done. Now you can publish your common code.


Consuming the code

  1. Install the infra. In our case the user have to use: npm install my-js-infra --save
  2. Modify the tsconfig.json of the consuming application to load the modules using the Node module resolution. You do so by setting moduleResolution:true inside the file.

Here's my tsconfig.json:

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["es5", "es6"],
        "module": "umd",
        "sourceMap": true,
        "watch": false,
        "outDir": "./tsOutputs",
        "moduleResolution":"node" /* This must be specified in order for typescript to find the my-js-infra. Another option is to use "paths" and "baseUrl". Something like:
                                        ...
                                        "baseUrl": ".", // This must be specified if "paths" is used.
                                        "paths":{
                                            "my-js-infra":["node_modules/my-js-infra/tsOutputs/index.d.ts"]
                                        }
                                        ...
                                    */
    }
}

You can read more on module resolution in Typescript in here: https://www.typescriptlang.org/docs/handbook/module-resolution.html

  1. Start using the code. For example:

import {MyJsInfra } from "my-js-infra";

public doMagic(cmd, callback) {
        try {
            var request:MyJsInfra.Entities.HttpRequest = {
                verb: "GET",
                url: "http://www.google.com",
            };

            var client = new MyJsInfra.HttpClient();
            client.doRequest(request, (err, data)=>{
                if (err)
                    return callback(err, null)
                return callback(null, data);
            })
        } catch (err) {
            callback(err);
        }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM