TS Patch
Directly patch typescript installation to allow custom transformers (plugins).
- Plugins are specified in
tsconfig.json
, or provided programmatically in CompilerOptions
. - Based on ttypescript - Fully compatible + offers more features
TypeScript v5 Note
TS v5 has made some fundamental changes which affect the current process. As a result, it is not yet supported.
We're working on adding support. More notes on that here:
Features
- Patch / unpatch any version of typescript (4.*)
- Advanced options for patching individual libraries, specific locations, etc. (see
ts-patch /?
) - (New) Supports 'transforming' the
Program
instance during creation. (see: Transforming Program) - (New) Add, remove, or modify diagnostics! (see: Altering Diagnostics)
Setup
- Install package
<yarn|npm|pnpm> add -D ts-patch
- Patch typescript
# 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"
}
}
Table of Contents
Configuring
tsconfig.json
Add transformers to compilerOptions
in plugins
array.
Examples
{
"compilerOptions": {
"plugins": [
// Source Transformer: 'type' defaults to 'program'
{ "transform": "transformer-module", "someOption1": 123, "someOption2": 321 },
// Source Transformer: program signature
{ "transform": "./transformers/my-transformer.ts", "type": "program" },
// Source Transformer: program signature, applies after TS transformers
{ "transform": "transformer-module1", "type": "config", "after": true },
// Source Transformer: checker signature, applies to TS declarations
{ "transform": "transformer-module2", "type": "checker", "afterDeclarations": true },
// Source Transformer: raw signature
{ "transform": "transformer-module3", "type": "raw" },
// Source Transformer: compilerOptions signature
{ "transform": "transformer-module4", "type": "compilerOptions" },
// Program Transformer: Only has one signature - no type specified, because it does not apply
{ "transform": "transformer-module5", "transformProgram": true }
]
}
}
Plugin Options
Option | Type | Description |
---|
transform | string | Module name or path to transformer (*.ts or *.js) |
type | string | Source Transformer entry point signature (see: Source Transformer Signatures) |
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) |
after | boolean | Apply transformer after stock TS transformers. |
afterDeclarations | boolean | Apply transformer to declaration (*.d.ts) files (TypeScript 2.9+). |
transformProgram | boolean | Transform Program during ts.createProgram() (see: Transforming Program) |
... | | Provide your own custom options, which will be passed to the transformer |
Note: Required options are bold
Source Transformer Signatures
The following are the possible values for the type
option and their corresponding entry point signatures.
Note: These apply to Source Transformers only.
program (default)
Signature with ts.Program
instance:
(program: ts.Program, config: PluginConfig, extras: TransformerExtras) => ts.TransformerFactory
ts.TransformerFactory >>> (context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile
TransformerExtras >>> See Type Declaration
Note: This is not the configuration for a Program Transformer.
config
Signature with transformer's config:
(config: PluginConfig) => ts.TransformerFactory
checker
Signature with ts.TypeChecker
:
(checker: ts.TypeChecker, config: PluginConfig) => ts.TransformerFactory
raw
Signature without ts-patch
wrapper:
(context: ts.TransformationContext) => (sourceFile: ts.SourceFile) => ts.SourceFile
compilerOptions
(compilerOpts: ts.CompilerOptions, config: PluginConfig) => ts.TransformerFactory
Usage
Transforming AST Nodes
Transformers can be written in JS or TS.
import * as ts from 'typescript';
export default function(program: ts.Program, pluginOptions: any) {
return (ctx: ts.TransformationContext) => {
return (sourceFile: ts.SourceFile) => {
function visitor(node: ts.Node): ts.Node {
return ts.visitEachChild(node, visitor, ctx);
}
return ts.visitEachChild(sourceFile, visitor, ctx);
};
};
}
Example Node Transformers
{ transform: "typescript-transform-paths" }
{ transform: "typescript-is/lib/transform-inline/transformer" }
{ transform: "ts-transform-img/dist/transform", type: "config" }
{ transform: "ts-transform-css-modules/dist/transform", type: "config" }
{ transform: "ts-transform-react-intl/dist/transform", import: "transform", type: "config" }
{ transform: "ts-nameof", type: "raw" }
{ transform: "typescript-transform-jsx" }
{ transform: "ts-transformer-minify-privates" }
{ transform: "typia/lib/transform" }
Transforming Program
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.
Configuring Program Transformer
To configure a Program Transformer, supply "transformProgram": true
in the config transformer entry.
Note: The type
, before
, and after
options do not apply to a Program Transformer and will be ignored
See Config Example
Signature
There is only one possible signature for a Program Transformer entry point.
(program: ts.Program, host: ts.CompilerHost | undefined, options: PluginConfig, extras: ProgramTransformerExtras) => ts.Program
ProgramTransformerExtras >>> See Type Declaration
Example Program Transformer
import * as ts from 'typescript';
import * as path from 'path';
import { 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(
program.getRootFileNames().concat([ newFile ]),
program.getCompilerOptions(),
host,
program
);
}
Note: For a more complete example, see Transforming Program with additional AST transformations
Altering Diagnostics
Diagnostics can be altered in a Source Transformer.
To alter diagnostics, use the program type signature, and use the following properties from the
TransformerExtras
parameter
property | description |
---|
diagnostics | Reference to Diagnostic array |
addDiagnostic() | Directly add Diagnostic to diagnostics array |
removeDiagnostic() | Directly remove Diagnostic from diagnostics array (uses splice, for safe removal) |
Notes
- 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
Resources
Recommended Reading
Recommended Tools
Tool | Type | Description |
---|
TS AST Viewer | Website | Allows you to see the Node structure and other TS properties of your source code. |
ts-query | NPM Package | Perform fast CSS-like queries on AST to find specific nodes (by attribute, kind, name, etc) |
ts-query Playground | Website | Test ts-query in realtime |
ts-expose-internals | NPM Package | Exposes internal types and methods of the TS compiler API |
Credit
HALP!!!
License
This project is licensed under the MIT License, as described in LICENSE.md