Patch typescript to allow custom transformers (plugins) during build.
Plugins are specified in tsconfig.json
, or provided programmatically in CompilerOptions
.
Migrating from ttypescript is easy! See: Method 1: Live Compiler
- Patch typescript installation via on-the-fly, in-memory patching or as a persistent patch
- Can patch individual libraries (see
ts-patch /?
) - Hook build process by transforming the
Program
(see: Transforming Program) - Add, remove, or modify diagnostics (see: Altering Diagnostics)
- Fully compatible with legacy ttypescript projects
- (new) Experimental support for ES Module based transformers
- ts-patch
- Table of Contents
- Installation
- Usage
- Configuration
- Writing Transformers
- Advanced Options
- Maintainers
- License
- Install package
<yarn|npm|pnpm> add -D ts-patch
The live compiler patches on-the-fly, each time it is run.
Via commandline: Simply use tspc
(instead of tsc
)
With tools such as ts-node, webpack, ts-jest, etc: specify the compiler as ts-patch/compiler
Persistent patch modifies the typescript installation within the node_modules path. It requires additional configuration to remain persisted, but it carries less load time and complexity compared to the live compiler.
- Install the patch
# For advanced options, see: ts-patch /?
ts-patch install
- Add
prepare
script (keeps patch persisted after npm install)
package.json
{
/* ... */
"scripts": {
"prepare": "ts-patch install -s"
}
}
tsconfig.json: Add transformers to compilerOptions
in plugins
array.
Examples
{
"compilerOptions": {
"plugins": [
// Source Transformers
{ "transform": "transformer-module" },
{ "transform": "transformer2", "extraOption": 123 },
{ "transform": "trans-with-mapping", "resolvePathAliases": true },
{ "transform": "esm-transformer", "isEsm": true },
// Program Transformer
{ "transform": "transformer-module5", "transformProgram": true }
]
}
}
Option | Type | Description |
---|---|---|
transform | string | Module name or path to transformer (*.ts or *.js) |
after | boolean | Apply transformer after stock TS transformers |
afterDeclarations | boolean | Apply transformer to declaration (*.d.ts) files |
transformProgram | boolean | Transform Program during ts.createProgram() (see: Program Transformers) |
isEsm | boolean | Transformer is ES Module (note: experimental — requires esm) |
resolvePathAliases | boolean | Resolve path aliases in transformer (requires tsconfig-paths) |
type | string | See: Source Transformer Entry Point (default: 'program') |
import | string | Name of exported transformer function (defaults to default export) |
tsConfig | string | tsconfig.json file for transformer (allows specifying compileOptions, path mapping support, etc) |
... | Provide your own custom options, which will be passed to the transformer |
Note: Required options are bold
Source Transformers will transform the AST of SourceFiles during compilation, allowing you to alter the output of the JS or declarations files.
(program: ts.Program, config: PluginConfig, extras: TransformerExtras) => ts.TransformerFactory
PluginConfig: Type Declaration
TransformerExtras: Type Declaration
ts.TransformerFactory: (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile
Note: Additional legacy signatures are supported, but it is not recommended to develop a new transformer using them.
Transformers can be written in JS or TS.
import type * as ts from 'typescript';
import type { TransformerExtras, PluginConfig } from 'ts-patch';
/** Changes string literal 'before' to 'after' */
export default function (program: ts.Program, pluginConfig: PluginConfig, { ts: tsInstance }: TransformerExtras) {
return (ctx: ts.TransformationContext) => {
const { factory } = ctx;
return (sourceFile: ts.SourceFile) => {
function visit(node: ts.Node): ts.Node {
if (tsInstance.isStringLiteral(node) && node.text === 'before') {
return factory.createStringLiteral('after');
}
return tsInstance.visitEachChild(node, visit, ctx);
}
return tsInstance.visitNode(sourceFile, visit);
};
};
}
Live Examples:
{ transform: "typescript-transform-paths" }
{ transform: "typescript-is/lib/transform-inline/transformer" }
{ transform: "typia/lib/transform" }
(💻playground)
{ transform: "@nestia/core/lib/transform" }
Diagnostics can be altered in a Source Transformer.
To alter diagnostics you can use the following, provided from the TransformerExtras
parameter:
property | description |
---|---|
diagnostics | Reference to Diagnostic array |
addDiagnostic() | Safely add Diagnostic to diagnostics array |
removeDiagnostic() | Safely remove Diagnostic from diagnostics array |
This alters diagnostics during emit only. If you want to alter diagnostics in your IDE as well, you'll need to create a LanguageService plugin to accompany your source transformer
Sometimes you want to do more than just transform source code. For example you may want to:
- TypeCheck code after it's been transformed
- Generate code and add it to the program
- Add or remove emit files during transformation
For this, we've introduced what we call a Program Transformer. The transform action takes place during ts.createProgram
, and allows
re-creating the Program
instance that typescript uses.
(program: ts.Program, host: ts.CompilerHost | undefined, options: PluginConfig, extras: ProgramTransformerExtras) => ts.Program
ProgramTransformerExtras >>> Type Declaration
To configure a Program Transformer, supply "transformProgram": true
in the config transformer entry.
Note: The before
, after
, and afterDeclarations
options do not apply to a Program Transformer and will be ignored
/**
* Add a file to Program
*/
import * as path from 'path';
import type * as ts from 'typescript';
import type { ProgramTransformerExtras, PluginConfig } from 'ts-patch';
export const newFile = path.resolve(__dirname, 'added-file.ts');
export default function (
program: ts.Program,
host: ts.CompilerHost | undefined,
options: PluginConfig,
{ ts: tsInstance }: ProgramTransformerExtras
) {
return tsInstance.createProgram(
/* rootNames */ program.getRootFileNames().concat([ newFile ]),
program.getCompilerOptions(),
host,
/* oldProgram */ program
);
}
Note: For a more complete example, see Transforming Program with additional AST transformations
Live Examples:
{ transform: "@typescript-virtual-barrel/compiler-plugin", transformProgram: true }
- How-To: Advice for working with the TS Compiler API
- How-To: TypeScript Transformer Handbook
- Article: How to Write a TypeScript Transform (Plugin)
- Article: Creating a TypeScript Transformer
Tool | Type | Description |
---|---|---|
TS AST Viewer | Web App | Allows you to see the Node structure and other TS properties of your source code. |
ts-expose-internals | NPM Package | Exposes internal types and methods of the TS compiler API |
#compiler-internals-and-api
on TypeScript Discord Server- TSP Discussions Board
(env) TSP_SKIP_CACHE
Skips patch cache when patching via cli or live compiler.
(env) TSP_COMPILER_TS_PATH
Specify typescript library path to use for ts-patch/compiler
(defaults to require.resolve('typescript')
)
(env) TSP_CACHE_DIR
Override patch cache directory
(cli) ts-patch clear-cache
Cleans patch cache & lockfiles
Ron S. |
If you're interested in helping and have a high level of skill with the TS compiler API, please reach out!
This project is licensed under the MIT License, as described in LICENSE.md