@babel/plugin-transform-typescript · Babel (original) (raw)

info

This plugin is included in @babel/preset-typescript

This plugin adds support for the types syntax used by the TypeScript programming language. However, this plugin does not add the ability to type-check the JavaScript passed to it. For that, you will need to install and set up TypeScript.

Note that although the TypeScript compiler tsc actively supports certain JavaScript proposals such as optional chaining (?.), nullish coalescing (??) and class properties (this.#x), this preset does not include these features because they are not the types syntax available in TypeScript only. We recommend using preset-env with preset-typescript if you want to transpile these features.

Example

In

Out

Installation

npm install --save-dev @babel/plugin-transform-typescript

Usage

babel.config.json

{
  "plugins": ["@babel/plugin-transform-typescript"]
}

Via CLI

Shell

babel --plugins @babel/plugin-transform-typescript script.js

Via Node API

JavaScript

require("@babel/core").transformSync("code", {
  plugins: ["@babel/plugin-transform-typescript"],
});

Options

allowDeclareFields

boolean, defaults to false

Added in v7.7.0

note

This will be enabled by default in Babel 8

When enabled, type-only class fields are only removed if they are prefixed with the declare modifier:

JavaScript

class A {
  declare foo: string; // Removed
  bar: string; // Initialized to undefined
}

allowNamespaces

boolean, defaults to true.

History

Version Changes
v7.5.0 Added allowNamespaces, defaults to false
v7.13.0 defaults to true

Enables compilation of TypeScript namespaces.

disallowAmbiguousJSXLike

boolean, defaults to false

Added in: v7.16.0

Even when JSX parsing is not enabled, this option disallows using syntax that would be ambiguous with JSX (<X> y type assertions and <X>() => {} type arguments). It matches the tsc behavior when parsing .mts and .mjs files.

dts

boolean, defaults to false

Added in: v7.20.0

This option will enable parsing within a TypeScript ambient context, where certain syntax have different rules (like .d.ts files and inside declare module blocks). Please see Official Handbook and TypeScript Deep Dive for more information about ambient contexts.

isTSX

boolean, defaults to false

Forcibly enables jsx parsing. Otherwise angle brackets will be treated as TypeScript's legacy type assertion var foo = <string>bar;. Also, isTSX: true requires allExtensions: true.

jsxPragma

string, defaults to React.createElement

Replace the function used when compiling JSX expressions. This is so that we know that the import is not a type import, and should not be removed.

jsxPragmaFrag

string, defaults to React.Fragment

Replace the function used when compiling JSX fragment expressions. This is so that we know that the import is not a type import, and should not be removed.

onlyRemoveTypeImports

boolean, defaults to false

Added in: v7.9.0

When set to true, the transform will only remove type-only imports (introduced in TypeScript 3.8). This should only be used if you are using TypeScript >= 3.8.

JavaScript

class A {
  declare foo: string; // Removed
  bar: string; // Initialized to undefined
  prop?: string; // Initialized to undefined
  prop1!: string // Initialized to undefined
}

optimizeConstEnums

boolean, defaults to false

Added in: v7.15.0

When set to true, Babel will inline enum values rather than using the usual enum output:

// Input
const enum Animals {
  Fish,
}
console.log(Animals.Fish);

// Default output
var Animals;

(function(Animals) {
  Animals[(Animals["Fish"] = 0)] = "Fish";
})(Animals || (Animals = {}));

console.log(Animals.Fish);

// `optimizeConstEnums` output
console.log(0);

This option differs from TypeScript's --isolatedModules behavior, which ignores the const modifier and compiles them as normal enums, and aligns Babel's behavior with TypeScript's default behavior.

However, when exporting a const enum Babel will compile it to a plain object literal so that it doesn't need to rely on cross-file analysis when compiling it:

// Input
export const enum Animals {
  Fish,
}

// `optimizeConstEnums` output
export var Animals = {
  Fish: 0,
};

TypeScript Compiler Options

The official TypeScript compiler has many options for configuring how it compiles and type checks. While many don't apply, some behaviors might be useful and their equivalents in Babel can be enabled by some configuration options or plugins.

module.exports = {  
  parserOpts: { strictMode: true },  
};  
module.exports = {  
  plugins: [["@babel/plugin-proposal-decorators", { legacy: true }]],  
};  

Caveats

Because there are features of the TypeScript language which rely on the full type-system to be available to make changes at runtime. This section of caveats is quite long, however, it's worth noting that a few of these features are only found in older TypeScript codebases and have modern JavaScript equivalents which you are probably already using.

  1. Since Babel does not type-check, code which is syntactically correct, but would fail the TypeScript type-checking may successfully get transformed, and often in unexpected or invalid ways.
  2. Changes to your tsconfig.json are not reflected in babel. The build process will always behave as though isolatedModules is turned on, there are Babel-native alternative ways to set a lot of the tsconfig.json options however.
  3. Q: Why doesn't Babel allow export of a var or let?
    A: The TypeScript compiler dynamically changes how these variables are used depending on whether or not the value is mutated. Ultimately, this depends on a type-model and is outside the scope of Babel. A best-effort implementation would transform context-dependent usages of the variable to always use the Namespace.Value version instead of Value, in case it was mutated outside of the current file. Allowing var or let from Babel (as the transform is not-yet-written) is therefore is more likely than not to present itself as a bug when used as-if it was not const.

Impartial Namespace Support

If you have existing code which uses the TypeScript-only namespace features. Babel supports a subset of TypeScript's namespace features. If you are considering writing new code which uses namespace, using the ES2015 import/export is recommended instead. It's not going away, but there are modern alternatives.

namespace N {  
  export const V = 1;  
}  
namespace N {  
  export const W = V;  
}  

The TypeScript compiler compiles it to something like this:
JavaScript

var N = {};  
(function(N) {  
  N.V = 1;  
})(N);  
(function(N) {  
  N.W = N.V;  
})(N);  

While Babel will transform it to something like this:
JavaScript

var N;  
(function(_N) {  
  const V = (_N = 1);  
})(N || (N = {}));  
(function(_N) {  
  const W = V;  
})(N || (N = {}));  

As Babel doesn't understand the type of N, the reference to V will be undefined resulting in an error.
Workaround: Explicitly refer to values not in the same namespace definition, even if they would be in the scope according to TypeScript. Examples:

namespace N {  
  export const V = 1;  
}  
namespace N {  
  export const W = N.V;  
}  

Or:

namespace N {  
  export const V = 1;  
  export const W = V;  
}