A simple tool for creating d.ts
in egg application. Injecting controller, proxy, service, etc.
to definition type of egg ( such as Context
Application
etc. ) by Declaration Merging, and making IntelliSense works in both egg-js and egg-ts.
open your application and install.
npm i egg-ts-helper --save-dev
or
yarn add egg-ts-helper --dev
Open your egg application, executing ets by npx
$ npx ets
Watching files by -w
flag.
$ npx ets -w
If you don't want to use npx, just install it in global or use register
in egg-bin
.
$ egg-bin dev -r egg-ts-helper/register
$ ets -h
Usage: ets [commands] [options]
Options:
-v, --version Output the version number
-w, --watch Watching files, d.ts will recreate if file is 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.js)
-o, --oneForAll [path] Create a d.ts import all types (default: typings/ets.d.ts)
-s, --silent Running without output
-i, --ignore [dirs] Ignore watchDirs, your can ignore multiple dirs with comma like: -i controller,service
-e, --enabled [dirs] Enable watchDirs, 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 when it has same name ts file
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'} |
watch | boolean |
false | watch file change or not |
watchOptions | object |
undefined | chokidar options |
execAtInit | boolean |
false | execute d.ts generation while instance was created |
configFile | string |
{cwd}/tshelper.js | configure file path |
watchDirs | object |
generator configuration |
You can configure the options above in ./tshelper.js
or package.json
.
In tshelper.js
// {cwd}/tshelper.js
module.exports = {
watch: true,
execAtInit: true,
watchDirs: {
model: {
enabled: true,
generator: "function",
interfaceHandle: "InstanceType<{{ 0 }}>"
},
}
}
In package.json
// {cwd}/package.json
{
"egg": {
"framework": "egg",
"tsHelper": {
"watch": true,
"execAtInit": true,
"watchDirs": {
"model": {
"enabled": true,
"generator": "function",
"interfaceHandle": "InstanceType<{{ 0 }}>"
},
}
}
}
}
Generator is the core of egg-ts-helper
. ( build-in generator: https://github.com/whxaxes/egg-ts-helper/tree/master/src/generators
)
On egg-ts-helper
startup, it will executes all watcher's generator for traversing directories and collect modules, after executing, generator return fields dist
( d.ts file path ) and content
( import these modules and defined to interface of egg. ) to egg-ts-helper
, then writes content
to dist
( remove file if content
is undefined ).
Watcher can be configured in option watchDirs
( see getDefaultWatchDirs
method in https://github.com/whxaxes/egg-ts-helper/blob/master/src/index.ts to know default config of watcher ). egg-ts-helper
watch these directories app/extend
,app/controller
,app/service
, app/config
, app/middleware
, app/model
by default. The d.ts
will be recreated when files under these folders are changed ( config.watch should set to true
) .
You can disable watcher by -i
flag.
$ ets -i extend,controller
Or in tshelper.js
, setting watchDirs.extend
and watchDirs.controller
to false
.
// {cwd}/tshelper.js
module.exports = {
watchDirs: {
extend: false,
controller: false,
}
}
Or in package.json
, setting is the same as above.
// {cwd}/package.json
{
"egg": {
"framework": "egg",
"tsHelper": {
"watchDirs": {
"extend": false
}
}
}
}
egg-ts-helper
using generator to implement feature like loader in egg. and it also support custom loader.
See the example below to know how to configure.
Creating d.ts
for model
by egg-ts-helper
. Setting watchDirs.model
in tshelper.js
.
// ./tshelper.js
module.exports = {
watchDirs: {
model: {
path: 'app/model', // dir path
// pattern: '**/*.(ts|js)', // glob pattern, default is **/*.(ts|js). it doesn't need to configure normally.
generator: 'class', // generator name
interface: 'IModel', // interface name
declareTo: 'Context.model', // declare to this interface
// caseStyle: 'upper', // caseStyle for loader
// interfaceHandle: val => `ReturnType<typeof ${val}>`, // interfaceHandle
// trigger: ['add', 'unlink'], // recreate d.ts when receive these events, all events: ['add', 'unlink', 'change']
}
}
}
The configuration can create d.ts in below.
import Station from '../../../app/model/station';
declare module 'egg' {
interface Context {
model: IModel;
}
interface IModel {
Station: Station;
}
}
the options using to configure watcher
- path
- pattern
- generator
- caseStyle
- interface
- interfaceHandle
- trigger
interface
set to IOther
.
interface IOther {
Station: Station;
}
It will use random interface name if interface
is not set.
interface T100 {
Station: Station;
}
Should set declareTo
if without interface
.
The name of generator, ( the generator will be executed and recreate d.ts
when the file is changed. ) but I recommend to use class
function
object
auto
only, because the other generator is not suitable for custom loader.
the types created by class
generator like below
interface IModel {
Station: Station;
}
suitable for module like this
export default class XXXController extends Controller { }
the types created by function
generator like below
interface IModel {
Station: ReturnType<typeof Station>;
}
suitable for module like this
export default () => {
return {};
}
the types created by object
generator like below.
interface IModel {
Station: typeof Station;
}
suitable for module like this
export default {}
the types created by auto
generator like below. It will check types automatically.
type AutoInstanceType<T, U = T extends (...args: any[]) => any ? ReturnType<T> : T> = U extends { new (...args: any[]): any } ? InstanceType<U> : U;
interface IModel {
Station: AutoInstanceType<typeof Station>;
}
suitable for every module in above.
module.exports = {
watchDirs: {
model: {
...
interfaceHandle: val => `${val} & { [key: string]: any }`,
}
}
}
The generated typings.
interface IModel {
Station: Station & { [key: string]: any };
}
The type of interfaceHandle
can be string
( Support since 1.18.0
)
module.exports = {
watchDirs: {
model: {
...
interfaceHandle: '{{ 0 }} & { [key: string]: any }',
}
}
}
The generated typings are the same as above. {{ 0 }}
means the first argument in function.
caseStyle
can set to lower
γupper
γcamel
or function
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
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
import Station from '../../../app/model/station';
declare module 'egg' {
interface Application {
model: {
subModel: IModel;
}
}
interface IModel {
Station: Station;
}
}
// ./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 = {
watchDirs: {
model: {
path: 'app/model',
generator: myGenerator,
trigger: ['add', 'unlink'],
}
}
}
or define generator to other js.
// ./my-generator.js
// 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
// ./tshelper.js
module.exports = {
watchDirs: {
model: {
path: 'app/model',
generator: './my-generator',
trigger: ['add', 'unlink'],
}
}
}
egg-ts-helper
offers a register.js
for easier to use with egg-bin.
$ egg-bin dev -r egg-ts-helper/register
test/coverage/debugging
$ egg-bin test -r egg-ts-helper/register
$ egg-bin cov -r egg-ts-helper/register
$ egg-bin debug -r egg-ts-helper/register
egg-ts-helper
can works in both ts
and js
egg project.