# egg-ts-helper [![NPM version][npm-image]][npm-url] [![Package Quality](http://npm.packagequality.com/shield/egg-ts-helper.svg)](http://packagequality.com/#?package=egg-ts-helper) [![Build Status][travis-image]][travis-url] [![Appveyor status][appveyor-image]][appveyor-url] [![Test coverage][codecov-image]][codecov-url] [![NPM download][download-image]][download-url] [npm-image]: https://img.shields.io/npm/v/egg-ts-helper.svg?style=flat-square [npm-url]: https://npmjs.org/package/egg-ts-helper [travis-url]: https://travis-ci.org/whxaxes/egg-ts-helper [travis-image]: http://img.shields.io/travis/whxaxes/egg-ts-helper.svg [appveyor-url]: https://ci.appveyor.com/project/whxaxes/egg-ts-helper/branch/master [appveyor-image]: https://ci.appveyor.com/api/projects/status/github/whxaxes/egg-ts-helper?branch=master&svg=true [codecov-image]: https://codecov.io/gh/whxaxes/egg-ts-helper/branch/master/graph/badge.svg [codecov-url]: https://codecov.io/gh/whxaxes/egg-ts-helper [download-image]: https://img.shields.io/npm/dm/egg-ts-helper.svg?style=flat-square [download-url]: https://npmjs.org/package/egg-ts-helper [easter-image]: https://img.shields.io/badge/easter%20egg-none-brightgreen.svg?style=flat-square A simple tool for creating `d.ts` in [egg](https://eggjs.org) application. Injecting `controller, proxy, service, etc.` to definition type of egg ( such as `Context` `Application` etc. ) by [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html), and making IntelliSense works in both egg-js and egg-ts. ## Install open your application and install. ``` npm i egg-ts-helper --save-dev ``` or ``` yarn add egg-ts-helper --dev ``` ## QuickStart Open your egg application, executing ets by [npx](https://github.com/zkat/npx) ``` $ npx ets ``` Watching files by `-w` flag. ``` $ npx ets -w ``` `egg-ts-helper` has build-in in `egg-bin`, You can easily to use it by ``` $ egg-bin dev --dts ``` or add configuration `egg.declarations` in `package.json` ## CLI ``` $ ets -h Usage: bin [commands] [options] Options: -v, --version output the version number -w, --watch Watching files, d.ts would recreated while file changed -c, --cwd [path] Egg application base dir (default: process.cwd) -C, --config [path] Configuration file, The argument can be a file path to a valid JSON/JS configuration file.(default: {cwd}/tshelper -o, --oneForAll [path] Create a d.ts import all types (default: typings/ets.d.ts) -s, --silent Running without output -i, --ignore [dirs] Ignore generator, your can ignore multiple dirs with comma like: -i controller,service -e, --enabled [dirs] Enable generator, your can enable multiple dirs with comma like: -e proxy,other -E, --extra [json] Extra config, the value should be json string -h, --help output usage information Commands: clean Clean js file while it has the same name ts/tsx file init Init egg-ts-helper in your existing project ``` ## Configuration | name | type | default | description | | --- | --- | --- | --- | | cwd | `string` | process.cwd | egg application base dir | | typings | `string` | {cwd}/typings | typings dir | | caseStyle | `string` `Function` | lower | egg case style(lower,upper,camel) or `(filename) => {return 'YOUR_CASE'}`| | silent | `boolean` | false | ignore logging | | watch | `boolean` | false | watch file change or not, default to `true` in `register` | | watchOptions | `object` | undefined | chokidar [options](https://github.com/paulmillr/chokidar#api) | | autoRemoveJs | `boolean` | true | auto remove same name js on startup | | configFile | `string` | {cwd}/tshelper.(js|json) | configure file path | | generatorConfig | `object` | | generator configuration( watchDirs has been deprecated ) | You can configure the options above in `./tshelper.js` `./tshelper.json` or `package.json`. In `tshelper.js` ```js // {cwd}/tshelper.js module.exports = { generatorConfig: { model: { enabled: true, generator: "function", interfaceHandle: "InstanceType<{{ 0 }}>" }, } } ``` In `tshelper.json` ```json // {cwd}/tshelper.json { "generatorConfig": { "model": { "enabled": true, "generator": "function", "interfaceHandle": "InstanceType<{{ 0 }}>" }, } } ``` In `package.json` ```json // {cwd}/package.json { "egg": { "framework": "egg", "tsHelper": { "generatorConfig": { "model": { "enabled": true, "generator": "function", "interfaceHandle": "InstanceType<{{ 0 }}>" } } } } } ``` or use `dot-prop` ```json // {cwd}/package.json { "egg": { "framework": "egg", "tsHelper": { "generatorConfig.model": { "enabled": true, "generator": "function", "interfaceHandle": "InstanceType<{{ 0 }}>" } } } } ``` Also you can pass options by env ( support since 1.22.0 ) - `ETS_CWD`: cwd - `ETS_FRAMEWORK`: framework - `ETS_TYPINGS`: typings - `ETS_CASE_STYLE`: caseStyle - `ETS_AUTO_REMOVE_JS`: autoRemoveJs - `ETS_THROTTLE`: throttle - `ETS_WATCH`: watch - `ETS_SILENT`: silent - `ETS_CONFIG_FILE`: configFile ## Custom Loader > Support since 1.24.0 `egg-ts-helper` support customLoader configuration of egg. see https://github.com/eggjs/egg/issues/3480 Configure in `config.default.ts` ```typescript 'use strict'; import { EggAppConfig, PowerPartial } from 'egg'; export default function(appInfo: EggAppConfig) { const config = {} as PowerPartial; config.keys = appInfo.name + '123123'; config.customLoader = { model: { directory: 'app/model', inject: 'app', caseStyle: 'upper', }, }; return { ...config as {}, ...bizConfig, }; } ``` `egg-ts-helper` will auto create the d.ts for files under `app/model` ```typescript // This file is created by egg-ts-helper@1.24.1 // Do not modify this file!!!!!!!!! import 'egg'; type AutoInstanceType any ? ReturnType : T> = U extends { new (...args: any[]): any } ? InstanceType : U; import ExportCastle from '../../../app/model/Castle'; import ExportUser from '../../../app/model/User'; declare module 'egg' { interface Application { model: T_custom_model; } interface T_custom_model { Castle: AutoInstanceType; User: AutoInstanceType; } } ``` And you can easily to use it in your code. ![image](https://user-images.githubusercontent.com/5856440/54109111-b4848b80-4418-11e9-9da5-77b342f7f814.png) ## Generator If you are using `loader.loadToApp` or `loader.loadToContext` to load the instance, you should use generator config. ### Example Creating `d.ts` for files under `app/model`. You should add config `generatorConfig.model` in your config file. ```typescript // ./tshelper.js module.exports = { generatorConfig: { model: { directory: 'app/model', // files directory. // pattern: '**/*.(ts|js)', // glob pattern, default is **/*.(ts|js). it doesn't need to configure normally. // ignore: '', // ignore glob pattern, default to empty. generator: 'class', // generator name, eg: class、auto、function、object interface: 'IModel', // interface name declareTo: 'Context.model', // declare to this interface // watch: true, // whether need to watch files // caseStyle: 'upper', // caseStyle for loader // interfaceHandle: val => `ReturnType`, // interfaceHandle // trigger: ['add', 'unlink'], // recreate d.ts when receive these events, all events: ['add', 'unlink', 'change'] } } } ``` The configuration can create d.ts as below. > Attention, The type will merge into egg without any pre handling if the generator field is `class`, If you dont know how it works, just using `generator: 'auto'` instead. ```typescript import Station from '../../../app/model/station';// <-- find all files under app/model and import then. declare module 'egg' { interface Context { // <-- Context is reading from `declareTo` model: IModel; // <-- IModel is reading from `interface`, It will create a random interface if this field is empty } interface IModel { // <-- The same as above. Station: Station; // <-- Merging `Station` to IModel so we can use `ctx.model.Station` in code. } } ``` ### Effect of different options #### interface `string` `interface` set to `IOther`. ```typescript interface IOther { Station: Station; } ``` It will use random interface if `interface` is not set. ```typescript interface T100 { Station: Station; } ``` Attentions: Must set `declareTo` if `interface` is not set. #### generator `string` The name of generator, available value is `class` `function` `object` `auto`. **`generator: 'class'`** the types created by `class` generator as below ```typescript interface IModel { Station: Station; } ``` It's suitable for module wrote like this ```typescript export default class XXXController extends Controller { } ``` **`generator: 'function'`** ( Support since `1.16.0` ) the types created by `function` generator as below ```typescript interface IModel { Station: ReturnType; // Using ReturnType to get return type of function. } ``` It's suitable for module like this ```typescript export default () => { return {}; } ``` **`generator: 'object'`** ( Support since `1.16.0` ) the types created by `object` generator as below. ```typescript interface IModel { Station: typeof Station; } ``` It's suitable for module like this ```typescript export default {} ``` **`generator: 'auto'`** ( Support since `1.19.0` ) the types created by `auto` generator as below. It will check types automatically. ```typescript type AutoInstanceType any ? ReturnType : T> = U extends { new (...args: any[]): any } ? InstanceType : U; interface IModel { Station: AutoInstanceType; } ``` It's suitable for every module in above. #### interfaceHandle `function|string` If you cannot find suitable generator in above, you can config the type by this field. ```js module.exports = { generatorConfig: { model: { ... interfaceHandle: val => `${val} & { [key: string]: any }`, } } } ``` The generated typings. ```typescript interface IModel { Station: Station & { [key: string]: any }; } ``` The type of `interfaceHandle` can be `string` ( Support since `1.18.0` ) ```js module.exports = { generatorConfig: { model: { ... interfaceHandle: '{{ 0 }} & { [key: string]: any }', } } } ``` The generated typings are the same as above. `{{ 0 }}` means the first argument in function. #### caseStyle `function|string` `caseStyle` can set to `lower`、`upper`、`camel` or function #### declareTo `string` Declaring interface to definition of egg. ( Support since `1.15.0` ) `declareTo` set to `Context.model` , and you can get intellisense by `ctx.model.xxx` ```typescript import Station from '../../../app/model/station'; declare module 'egg' { interface Context { model: IModel; } interface IModel { Station: Station; } } ``` `declareTo` set to `Application.model.subModel`, and you can get intellisense by `app.model.subModel.xxx` ```typescript import Station from '../../../app/model/station'; declare module 'egg' { interface Application { model: { subModel: IModel; } } interface IModel { Station: Station; } } ``` ### Defining custom generator ```javascript // ./tshelper.js // custom generator function myGenerator(config, baseConfig) { // config.dir dir // config.dtsDir d.ts dir // config.file changed file // config.fileList file list console.info(config); console.info(baseConfig); // return type can be object or array { dist: string; content: string } | Array<{ dist: string; content: string }> // egg-ts-helper will remove dist file when content is undefined. return { dist: 'd.ts file url', content: 'd.ts content' } } module.exports = { generatorConfig: { model: { directory: 'app/model', generator: myGenerator, trigger: ['add', 'unlink'], } } } ``` or define generator to other js. ```javascript // ./my-generator.js module.exports.defaultConfig = { // default watchDir config } // custom generator module.exports = (config, baseConfig) => { // config.dir dir // config.dtsDir d.ts dir // config.file changed file // config.fileList file list console.info(config); console.info(baseConfig); // return type can be object or array { dist: string; content: string } | Array<{ dist: string; content: string }> // egg-ts-helper will remove dist file when content is undefined. return { dist: 'd.ts file url', content: 'd.ts content' } } ``` configure in `tshelper.js` or `package.json` ```js // ./tshelper.js module.exports = { generatorConfig: { model: { directory: 'app/model', generator: './my-generator', trigger: ['add', 'unlink'], } } } ``` ## Demo `egg-ts-helper` can works in both `ts` and `js` egg project. TS demo: https://github.com/whxaxes/egg-boilerplate-d-ts JS demo: https://github.com/whxaxes/egg-boilerplate-d-js