Upgrade to Babel 8 (API)
This document lists the breaking changes introduced in Babel 8.0.0, and how to adapt your usage of Babel to them when upgrading from Babel 7.0.0. This document is intended for developers using Babel's API directly, such as Babel plugin authors, or authors of projects that use Babel as a library.
Check out the Babel 8 migration guide first to learn about user-facing breaking changes.
AST Changes
JavaScript nodes
- Represent dynamic
import()with anImportExpressionnode (#15682, #16114).Migration: You are encouraged to test your Babel plugins with the new AST, starting from v7.23.0, specifying// Example input
import("foo", options);
// AST in Babel 7
{
type: "CallExpression",
callee: { type: "Import" },
arguments: [
StringLiteral("foo"),
Identifier("options")
]
}
// AST in Babel 8
{
type: "ImportExpression",
source: StringLiteral("foo"),
options: Identifier("options")
}{ parserOpts: { createImportExpressions: true } }in the Babel config. For end users utilizing Babel plugins that rely on the legacyimport()AST, it is possible to setcreateImportExpressionstofalse. Note that the Babel 7import()AST is now considered deprecated, it does not support new ES features such as Source Phrase Imports. We will remove thecreateImportExpressionsparser option in Babel 9.
-
Use
bigintforBigIntLiteral.value, rather than a string(#17378)// Example input
0xff01_0000_0000_0000_0000_0000_0000_0001n
// AST in Babel 7
{
type: "BigIntLiteral",
value: "0xff010000000000000000000000000001",
extra: {
rawValue: "0xff010000000000000000000000000001",
raw: "0xff01_0000_0000_0000_0000_0000_0000_0001n",
}
}
// AST in Babel 8
{
type: "BigIntLiteral",
value: 338958331222012082418099330867817086977n,
extra: {
rawValue: 338958331222012082418099330867817086977n,
raw: "0xff01_0000_0000_0000_0000_0000_0000_0001n"
}
}Migration: This change aligns with how we handle
NumericLiteral. If you want to access string representation in Babel 7, call thetoString()bigint instance method. Note that the builtin JavaScript methodJSON.stringifycan not serializebigint. If you want to store the Babel 8 AST as JSON, you can provide your ownbigintserializer.
TypeScript nodes
Most of the changes to our TypeScript-specific AST nodes are to reduce the differences with the AST shape of the @typescript-eslint project. This will make it easier to write ESLint rules that, when not depending on type information, can work both with @typescript-eslint/parser and @babel/eslint-parser.
-
Use an identifier for
TSTypeParameter.name, rather than a plain string (#12829)input.ts// T is a TSTypeParameter
function process<T>(input: T): T {}
// AST in Babel 7
{
type: "TSTypeParameter",
name: "T",
}
// AST in Babel 8
{
type: "TSTypeParameter",
name: { type: "Identifier", name: "T" },
} -
Allow
ThisExpressionasTSTypeQuery.exprName, rather than athisidentifier (#17059)input.tsfunction fn() {
// `typeof this` is a TSTypeQuery
var self: typeof this
}
// AST in Babel 7
{
type: "TSTypeQuery",
exprName: { type: "Identifier", name: "this" }
}
// AST in Babel 8
{
type: "TSTypeQuery",
exprName: { type: "ThisExpression" }
} -
Parse exporting
TSImportEqualsDeclarationas anExportNamedDeclaration(#17073)Note that the
isExportfield is also removed. For anyTSImportEqualsDeclarationNodePathp, usep.parentPath.isExportNamedDeclaration()to detect whether it is following anexportkeyword.input.tsexport import foo = require("foo")
// AST in Babel 7
{
type: "TSImportEqualsDeclaration",
importKind: "value"
isExport: true,
id: Identifier("foo"),
moduleReference: {
type: "TSExternalModuleReference",
expression: StringLiteral("foo")
}
}
// AST in Babel 8
{
type: "ExportNamedDeclaration",
declaration: {
type: "TSImportEqualsDeclaration",
importKind: "value"
id: Identifier("foo"),
moduleReference: {
type: "TSExternalModuleReference",
expression: StringLiteral("foo")
}
},
specifiers: []
} -
Rename
parameterstoparamsandtypeAnnotationtoreturnTypeinTSCallSignatureDeclaration,TSConstructSignatureDeclaration,TSFunctionType,TSConstructorTypeandTSMethodSignature(#9231, #13709)TSCallSignatureDeclaration
input.tsinterface Foo {
(x: number): string;
}
// AST in Babel 7
{
type: "TSCallSignatureDeclaration",
parameters: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
typeAnnotation: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}
// AST in Babel 8
{
type: "TSCallSignatureDeclaration",
params: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
retutnType: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}TSConstructSignatureDeclaration
input.tsinterface Foo {
new (x: number): string;
}
// AST in Babel 7
{
type: "TSConstructSignatureDeclaration",
parameters: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
typeAnnotation: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}
// AST in Babel 8
{
type: "TSConstructSignatureDeclaration",
params: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
retutnType: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}TSMethodSignature
input.tsinterface Foo {
foo(x: number): string;
}
// AST in Babel 7
{
type: "TSMethodSignature",
key: Identifier("foo"),
parameters: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
typeAnnotation: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}
// AST in Babel 8
{
type: "TSMethodSignature",
key: Identifier("foo"),
params: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
retutnType: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}TSFunctionType
input.tstype Bar = (x: number) => string;
// AST in Babel 7
{
type: "TSFunctionType",
parameters: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
typeAnnotation: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}
// AST in Babel 8
{
type: "TSFunctionType",
params: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
retutnType: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}TSConstructorType
input.tstype Bar = (x: number) => string;
// AST in Babel 7
{
type: "TSConstructorType",
parameters: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
typeAnnotation: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
}
// AST in Babel 8
{
type: "TSConstructorType",
params: [
{ type: "Identifier", name: "x", typeAnnotation: { type: "TSNumberKeyword" } }
],
retutnType: {
type: "TSTypeAnnotation",
typeAnnotation: { type: "TSStringKeyword" }
}
} -
Rename
typeParameterstotypeArgumentsinCallExpression,JSXOpeningElement,NewExpression,OptionalCallExpression,TSImportType,TSInstantiationExpression,TSTypeQueryandTSTypeReference(#16679, #17008, #17012, #17020, #17042)CallExpression
input.tsfn<string>()
// AST in Babel 7
{
type: "CallExpression",
callee: Identifier("fn"),
arguments: [],
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "CallExpression",
callee: Identifier("fn"),
arguments: [],
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}JSXOpeningElement
input.ts<Component<string>/>
// AST in Babel 7
{
type: "JSXOpeningElement",
name: JSXIdentifier("Component"),
attributes: [],
selfClosing: true,
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "JSXOpeningElement",
name: JSXIdentifier("Component"),
attributes: [],
selfClosing: true,
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}NewExpression
input.tsnew Component<string>()
// AST in Babel 7
{
type: "NewExpression",
callee: Identifier("Component"),
arguments: [],
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "NewExpression",
callee: Identifier("Component"),
arguments: [],
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}OptionalCallExpression
input.tsfn?.<string>()
// AST in Babel 7
{
type: "OptionalCallExpression",
callee: Identifier("fn"),
arguments: [],
optional: true,
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "OptionalCallExpression",
callee: Identifier("fn"),
arguments: [],
optional: true,
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}TSImportType
input.tsvar arr: import("./Array")<string>
// AST in Babel 7
{
type: "TSImportType",
argument: StringLiteral("./Array"),
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "TSImportType",
argument: {
type: "TSLiteralType",
literal: StringLiteral("./Array")
},
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}TSInstantiationExpression
input.tsfn<string>
// AST in Babel 7
{
type: "TSInstantiationExpression",
expression: Identifier("fn"),
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "TSInstantiationExpression",
expression: Identifier("fn"),
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}TSTypeQuery
input.tsvar arr: typeof Array<string>;
// AST in Babel 7
{
type: "TSTypeQuery",
exprName: Identifier("Array"),
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "TSTypeQuery",
exprName: Identifier("Array"),
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}TSTypeReference
input.tsvar arr: Array<string>;
// AST in Babel 7
{
type: "TSTypeReference",
typeName: Identifier("Array"),
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "TSTypeReference",
typeName: Identifier("Array"),
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
} -
Rename
superTypeParameterstosuperTypeArgumentsinClassDeclarationandClassExpression(#16679, #16997)input.tsclass X extends Y<string> {}
// AST in Babel 7
{
type: "ClassDeclaration",
id: Identifier("X"),
superClass: Identifier("Y"),
superTypeParameters: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
}
// AST in Babel 8
{
type: "ClassDeclaration",
id: Identifier("X"),
superClass: Identifier("Y"),
superTypeArguments: {
type: "TSTypeParameterInstantiation",
params: [{
type: "TSStringKeyword"
}]
}
} -
Split
typeParameterofTSMappedType(#16733).In
TSMappedTypenodes, thetypeParameterproperty is flattened askeyandconstraintproperties ofTSMappedTypeitself.input.tslet map1: { [P in string]: number; };
// AST in Babel 7
{
type: "TSMappedType",
typeParameter: {
type: "TypeParameter",
name: Identifier("P"),
constraint: TSStringKeyword()
},
typeAnnotation: TSNumberKeyword(),
}
// AST in Babel 8
{
type: "TSMappedType",
key: Identifier("P"),
constraint: TSStringKeyword()
typeAnnotation: TSNumberKeyword(),
} -
Split
TSExpressionWithTypeArgumentsintoTSClassImplementsandTSInterfaceHeritage(#16731).The new nodes also use
typeArgumentsinstead oftypeParameters(#17017). If theexpressionis a TS qualified name (e.g.a.b), it will be parsed as aMemberExpression(#17139).TSClassImplements
input.tsclass C implements X<T> {}
// AST in Babel 7
{
type: "ClassDeclaration",
id: Identifier("C"),
implements: [
{
type: "TSExpressionWithTypeArguments",
expression: Identifier("X"),
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [TSTypeReference(Identifier("T"))]
}
}
],
body: ClassBody([]),
}
// AST in Babel 8
{
type: "ClassDeclaration",
id: Identifier("C"),
implements: [
{
type: "TSClassImplements",
expression: Identifier("X"),
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [TSTypeReference(Identifier("T"))]
}
}
],
body: ClassBody([]),
}TSInterfaceHeritage
input.tsinterface I extends X<T> {}
// AST in Babel 7
{
type: "TSInterfaceDeclaration",
id: Identifier("I"),
extends: [
{
type: "TSExpressionWithTypeArguments",
expression: Identifier("X"),
typeParameters: {
type: "TSTypeParameterInstantiation",
params: [TSTypeReference(Identifier("T"))]
}
}
],
body: TSInterfaceBody([]),
}
// AST in Babel 8
{
type: "TSInterfaceDeclaration",
id: Identifier("I"),
extends: [
{
type: "TSInterfaceHeritage",
expression: Identifier("X"),
typeArguments: {
type: "TSTypeParameterInstantiation",
params: [TSTypeReference(Identifier("T"))]
}
}
],
body: TSInterfaceBody([]),
}Qualified name
input.tsclass C implements X.Y {}
// AST in Babel 7
{
type: "ClassDeclaration",
id: Identifier("C"),
implements: [
{
type: "TSExpressionWithTypeArguments",
expression: {
type: "TSQualifiedName",
left: Identifier("X"),
right: Identifier("Y")
}
}
],
body: ClassBody([]),
}
// AST in Babel 8
{
type: "ClassDeclaration",
id: Identifier("C"),
implements: [
{
type: "TSClassImplements",
expression: {
type: "MemberExpression",
object: Identifier("X"),
property: Identifier("Y"),
computed: false
}
}
],
body: ClassBody([]),
} -
Wrap the
argumentofTSImportTypewithin aTSLiteralType(#17046)The
TSImportTypealso usestypeArgumentsinstead oftypeParameters(#17042). See here for an example.input.tsvar arr: import("./Array")
// AST in Babel 7
{
type: "TSImportType",
argument: StringLiteral("./Array")
}
// AST in Babel 8
{
type: "TSImportType",
argument: {
type: "TSLiteralType",
literal: StringLiteral("./Array")
}
} -
Wrap the
membersofTSEnumDeclarationwithin aTSEnumBodynode (#16979)input.ts// Example input
enum ColorType {
Red,
Green,
Blue,
}
// AST in Babel 7
{
type: "TSEnumDeclaration",
id: Identifier("ColorType")
members: [
EnumMember("Red"),
EnumMember("Green"),
EnumMember("Blue")
]
}
// AST in Babel 8
{
type: "TSEnumDeclaration",
id: Identifier("ColorType")
body: {
type: "TSEnumBody",
members: [
EnumMember("Red"),
EnumMember("Green"),
EnumMember("Blue")
]
}
} -
Create
TSTemplateLiteralTypewhen there is at least one interpolated positionNote that the AST is not changed when there is no interpolated position, e.g.
`foo`as a template literal type is still parsed as a TemplateLiteral node within a TSLiteralType.input.tstype World = "world";
// `hello ${World}` is a template literal type
type Greeting = `hello ${World}`;
// AST in Babel 7
{
type: "TSLiteralType",
literal: {
type: "TemplateLiteral",
expressions: [{
type: "TSTypeReference",
typeName: Identifier("World")
}],
quasis: [
TemplateElement("hello "),
TemplateElement("")
]
}
}
// AST in Babel 8
{
type: "TSTemplateLiteralType",
types: [{
type: "TSTypeReference",
typeName: Identifier("World")
}],
quasis: [
TemplateElement("hello "),
TemplateElement("")
]
} -
Create
TSAbstractMethodDefinitionandTSPropertyDefinitionwhen bothestreeandtypescriptparser plugins are enabled (#16679, #17014)Migration: This breaking change is part of the efforts to libraries and ESLint plugins that can work both with
typescript-eslintand@babel/eslint-parser. For most Babel plugin developers you can safely ignore this change as it does not affect the typescript transform and codemod. That said, if you are trying to develop a custom ESLint rule with@babel/eslint-parser, this change aligns the Babel AST to thetypescript-eslintAST. -
Use
TSQualifiedNamefornamespace X.Y {}'s name (#16982)Rather than representing
namespace X.Y {}as two nestedTSModuleDeclarationnodes with namesXandY, it is now represented as a singleTSModuleDeclarationwhose name is aTSQualifiedName(X, Y). This change aligns the AST with the@typescript-eslintparser.// Example input
namespace X.Y {}
// AST in Babel 7
{
type: "TSModuleDeclaration",
id: Identifier("X"),
body: {
type: "TSModuleDeclaration",
id: Identifier("Y")
body: TSModuleBlock([]),
},
}
// AST in Babel 8
{
type: "TSModuleDeclaration",
id: {
type: "TSQualifiedName",
left: Identifier("X"),
right: Identifier("Y"),
},
body: TSModuleBlock([]),
}
-
Don't generate
TSParenthesizedTypeunlesscreateParenthesizedExpressionis enabled (#9546, #12608)input.tstype T = ({});
// Babel 8 with createParenthesizedExpression: true, and Babel 7
TSParenthesizedType { typeAnnotation: TSTypeLiteral { members: [] } }
// Babel 8 with createParenthesizedExpression: false
TSTypeLiteral { members: [] }Migration: If you need information about parentheses, specify the
createParenthesizedExpressionparser option.babel.config.json{ "parserOpts": { "createParenthesizedExpression": true } }When
createParenthesizedExpressionisfalse, you can also usenode.extra.parenthesizedto detect whethernodeis wrapped in parentheses.
API Changes
All packages
-
Disallow importing internal files (#14013, #14179).
Migration: Use the exported API only. If you are relying on Babel internals, please open an issue and let us know.
@babel/core
-
Disallow using
babel.transform,babel.transformFile,babel.transformFromAst,babel.parse,babel.loadOptions,babel.loadPartialConfigandbabel.createConfigItemsynchronously (#11110, #12695, #15869).Migration: The APIs above require a callback argument. If you are not providing a callback, please use their sync versions:
babel.transformSync,babel.transformFileSync,babel.transformFromAstSync,babel.parseSync,babel.loadOptionsSync,babel.loadPartialConfigSyncandbabel.createConfigItemSync.
@babel/generator
-
Remove
CodeGeneratorclass (#16126)Migration: In Babel 8 the undocumented
CodeGeneratorclass has been removed, please use the default exportedgeneratefunction instead.- new CodeGenerator(ast).generate()
+ generate(ast)
@babel/types
-
Reject invalid identifier names in
t.identifierbuilder (#10917).babel-plugin.js// Empty string is an invalid identifier name
t.identifier("");Migration: Call
t.identifierwith a valid name. -
Reject invalid variable declarator in
t.variableDeclarationbuilder (#10917, #17217)babel-plugin.js// var [x] is invalid without an initializer
t.variableDeclaration("var", [
t.variableDeclarator(t.arrayPattern([t.identifier("x")]))
]); -
Remove
Superfrom theExpressionalias (#14750).A
Supernode representssuperin super callsuper()and super propertysuper.foo. Assupercan not be a standalone expression,t.isExpression(t.super())will returnfalsein Babel 8.Migration: Search usage of the
t.isExpressionandt.assertsExpressionfunctions, and of thet.Expressiontype alias: if they need to also acceptSupernodes, update them accordingly.my-babel-plugin.js// Add `.foo` to an expression
- if (t.isExpression(path.node)) {
+ if (t.isExpression(path.node) || t.isSuper(path.node)) {
path.replaceWith(
t.memberExpression(
path.node,
t.identifier("foo")
))
}You don't have to update the usage if
super()andsuper.foois not involved:my-babel-plugin.js// define an expression as a computed key of `foo`
if (t.isExpression(path.node)) {
path.replaceWith(
t.memberExpression(
t.identifier("foo"),
// `super` can not be a computed key, so we don't update `isExpression`
path.node,
/* computed */ true
))
} -
Remove
AssignmentPatternandRestElementfrom theLValalias (#17387)An
LValnode represents valid nodes as the left hand side (LHS) of an assignment expression. AsAssignmentPatternandRestElementcan not be the LHS,t.isLVal(t.assignmentPattern(...))andt.isLVal(t.restElement(...))will returnfalsein Babel 8.Migration: Search usage of the
t.isLValandt.assertsLValfunctions, and of thet.LValtype alias: if they need to also acceptAssignmentPatternorRestElementnodes, you can broadent.LValwitht.PatternLike:my-babel-plugin.js// Iterate rest element within an object pattern
for (const propertyPath of path.get("properties")) {
- if (t.isLVal(propertyPath.node)) {
+ if (t.isLVal(propertyPath.node) || t.isPatternLike(propertyPath.node)) {
doSomethingWith(propertyPath);
}
} -
Remove
TSParameterPropertyfrom theLValalias (#17391)An
LValnode represents valid nodes as the left hand side (LHS) of an assignment expression. ATSParameterPropertyis a special function parameter type allowed only in a class constructor. SinceTSParameterPropertycan not be the LHS,t.isLVal(t.tsParameterProperty(...))will returnfalsein Babel 8. -
Require a
bigintas the only argument oft.bigIntLiteral(#17378)This is due to the corresponding AST shape change.
Migration: Pass the
bigintprimitive to thebigIntLiteralbuilder. Support ofbigintin thebigIntLiteralbuilder starts from Babel 7.28, you can begin the migration before you upgrade to Babel 8my-babel-codemod.jst.bigIntLiteral( -
"0xff020000000000000000000000000002"
- 0xff020000000000000000000000000002n )
- Require an `Identifier` node as the third argument of `t.tsTypeParameter` ([#12829](https://github.com/babel/babel/pull/12829))
This is due to the corresponding [AST shape change](#ast-TSTypeParameter).
__Migration__: Wrap the `name` string within the `identifier` builder
```diff title="my-babel-codemod.js"
t.tsTypeParameter(
/* constraint */ undefined,
/* default */ undefined,
+ t.identifier(
name
+ )
)
-
Require a
TSLiteralTypenode as the first argument oft.tsImportType(#17046)This is due to the corresponding AST shape change.
Migration: Wrap the
argumentstring literal within thetsLiteralTypebuildermy-babel-codemod.jst.tsImportType(
+ t.tsLiteralType(
t.stringLiteral("foo")
+ )
) -
Require a
TSEnumBodynode as the second argument oft.tsEnumDeclaration(#16979)This is due to the corresponding AST shape change.
Migration: Wrap the
membersarray within thetsEnumBodybuildermy-babel-codemod.js// Create `enum ColorType { Red, Green, Blue }`
t.tsEnumDeclaration(
t.identifier("ColorType"),
- [
+ t.tsEnumBody([
t.tsEnumMember(t.identifier("Red")),
t.tsEnumMember(t.identifier("Green")),
t.tsEnumMember(t.identifier("Blue"))
- ],
+ ]),
) -
Update the
t.tsMappedTypesignature (#16733)This is due to the corresponding AST shape change.
// Babel 7
declare function tsMappedType(
typeParameter: TSTypeParameter,
typeAnnotation?: TSType,
nameType?: TSType
): TSMappedType
// Babel 8
declare function tsMappedType(
key: Identifier,
constraint: TSType,
nameType?: TSType,
typeAnnotation?: TSType
): TSMappedTypeMigration: See the example below.
my-babel-codemod.ts// To create { [P in string as Q]: number }
// Babel 7
t.tsMappedType(
t.tsTypeParameter(t.tsStringKeyword(), undefined, "P"),
t.tsNumberKeyword(),
t.tsTypeReference(t.identifier("Q"))
)
// Babel 8
t.tsMappedType(
t.identifier("P"),
t.tsStringKeyword(),
t.tsTypeReference(t.identifier("Q")),
t.tsNumberKeyword()
) -
The second argument (
body) ofTSModuleDeclarationcannot be aTSModuleDeclarationanymore (#16982) -
The second argument (
body) oft.tsModuleDeclarationcannot be aTSModuleDeclarationnode anymore (#16982)Migration: Either create a
TSModuleBlockbody that exports theTSModuleDeclaration, or create a singleTSModuleDeclarationthat has aTSQualifiedNameas its name.my-babel-codemod.js// Option 1
// Create `namespace X.Y {}`
t.tsModuleDeclaration(
t.identifier("X"),
+ t.exportNamedDeclaration(
t.tsModuleDeclaration(
t.identifier("Y"),
t.tsModuleBlock([])
),
+ ),
)
```diff title="my-babel-codemod.js"
// Option 2
// Create `namespace X.Y {}`
t.tsModuleDeclaration(
+ t.tsQualifiedName(
t.identifier("X"),
- t.tsModuleDeclaration(
t.identifier("Y"),
+ ),
t.tsModuleBlock([])
- )
)
-
Remove
t.jSX*andt.tS*builder aliases (#6989, #15527)Migration: Use
t.jsx*andt.ts*instead. For example, replacet.jSXIdentifier("foo")witht.jsxIdentifier("foo"). -
Remove
selfClosingargument fromt.jsxElement(#14464)- t.jsxElement(openingElement, closingElement, children, selfClosing?: boolean)
+ t.jsxElement(openingElement, closingElement, children)Migration: The
selfClosingargument was already not used in the builder. You can safely remove it. -
Remove
optionalargument fromt.memberExpression(#13407)- t.memberExpression(object, property, computed, optional?: boolean)
+ t.memberExpression(object, property, computed)Migration: The
optionalargument was already not used in the builder. You can safely remove it. -
Remove the
Noopnode type (#12361)Migration: There is no generic migration path: you should replace it with the actual node that
Noopis being used as a placeholder for. If you are depending onNoopand have no alternative, please open an issue and explain your use case. -
Initialize
indexers,callPropertiesandinternalSlotsin the nodeObjectTypeAnnotationas an empty array int.objectTypeAnnotation(#14465)In Babel 7 the builder
t.objectTypeAnnotationinitializes them asnull, this is inconsistent with how@babel/parserwill parse the Flow object type annotations. In Babel 8 the new default value[]matches the parser behaviour. -
Reject negative and NaN/infinite numbers from
t.numericLiteral(#15802)babel-plugin.js// NumericLiterals must be non-negative finite numbers.
t.numericLiteral(-1);Migration: To represent a negative number, use
t.unaryExpression("-", t.numericLiteral(1)). To represent NaN or Infinity, uset.identifier("NaN"). To convert a generic numeric value (which could also be negative, NaN, or an inifinity) to the proper AST node, uset.valueToNode(num).
@babel/parser
Other than the changes listed below, @babel/parser is affected by all the AST changes.
-
Align Babel parser error codes between Flow and TypeScript (#13294)
The
error.codeforOptionalBindingPatternis renamed asPatternIsOptional. -
Remove
updateContextfield fromtokens[].typereturned from optiontokens: true(#13768)babel-integration.jsimport { parse } from "@babel/parser";
const { tokens } = parse("a = 42", { tokens: true });
tokens[0].type;
// Babel 7
// { label: "name", updateContext: null, ...other properties }
// Babel 8
// { label: "name", ... other properties }Note that
tokens[].typeis meant to be an opaque object used as an identity for token types, as if it was a symol. Its exact shape is meant to be an internal implementation detail. -
Tokenize private names (
#priv) as a singleprivateNametoken (#13256)babel-integration.jsimport { parse } from "@babel/parser";
const { tokens } = parse("class C { #priv }", { tokens: true });
tokens.filter(t => t.start >= 10 && t.end <= 15) // get tokens for `#priv`
// Babel 7
// [
// Token (#) { value: "#", start: 10, end: 11 },
// Token (name) { value: "priv", start: 11, end: 15 }
// ]
// Babel 8
// [
// Token (privateName) { value: "priv", start: 10, end: 15 }
// ] -
Tokenize template literals as
templateNonTailandtemplateTail(#13919)babel-integration.jsimport { parse } from "@babel/parser";
const { tokens } = parse("`head${x}middle${y}tail`", { tokens: true });
console.log(tokens); // print tokens
// Babel 7
// [
// Token (`),
// Token (template) { value: "head" }, Token (${),
// Token (name) { value: "x" }, Token (}),
// Token (template) { value: "middle" }, Token (${),
// Token (name) { value: "y" }, Token (}),
// Token (template) { value: "tail" }
// Token (`)
// ]
// Babel 8
// [
// Token (templateNonTail) { value: "head" },
// Token (name) { value: "x" },
// Token (templateNonTail) { value: "middle" },
// Token (name) { value: "y" },
// Token (templateTail) { value: "tail" }
// ] -
Remove
extra.shorthandfromObjectPropertynodes (#16521)Migration: Use
node.shorthandrather thannode.extra.shorthand.
@babel/traverse
-
Remove
is,isnt,has,equalsmethods fromNodePath(#16655)Migration: Directly compare properties of
path.nodeinstead.- functionExpressionPath.equals("id", idNode)
+ functionExpressionPath.node.id === idNode
- functionExpressionPath.is("id")
- functionExpressionPath.has("id")
+ functionExpressionPath.node.id
- functionExpressionPath.has("arguments")
+ !!functionExpressionPath.node.arguments.length
- functionExpressionPath.isnt("async")
+ !functionExpressionPath.node.async -
Remove
Scope.prototype.traverse,Scope#parentBlockandScope#hub(#16705)Migration: Use
scope.pathmethods and properties instead:- scope.traverse(scopeRootNode, visitor, state)
+ scope.path.traverse(visitor, state)
- scope.parentBlock
+ scope.path.parent
- scope.hub
+ scope.path.hub -
Remove
Scope.prototype.getAllBindingsOfKindandScope.prototype.toArray(#16705)These methods have been removed as they are not used anymore in our code base.
Migration: You can copy&paste them from Babel 7's source to your plugin.
-
Remove
hoist,updateSiblingKeys,call,setScope,resync,popContext,pushContext,setup,setKeymethods fromNodePath(#16655)These methods are meant to be private so there is no real migration approach. If your plugin / build is broken by this change, feel free to open an issue and tell us how you use these methods and we can see what we can do after Babel 8 is released.
-
Remove
blockargument fromScope#rename(#15288)- rename(oldName: string, newName?: string, block?: t.Pattern | t.Scopable)
+ rename(oldName: string, newName?: string)Migration: Instead of passing a different block to
scope.rename(), directly call.rename()on the scope corresponding to that block. -
Replace
Scope#uidsandScope#referenceswithScope#uidsSetandScope#referencesSet(#16624)They have been changed from objects with boolean values to
Setobjects. In addition to that, they are now only defined on the program scope (scope.getProgramParent()) rather than on all scope objects.- if (programScope.references["foo"])
+ if (programScope.referencesSet.has("foo")) -
Allow skipped
NodePaths to be requeued (#13291)NodePath#requeue()can requeue a skipped NodePath. This is actually a bugfix, but it causes an infinite loop in the temporal dead zone implementation of@babel/plugin-transform-block-scopingin Babel 7: it may break other plugins as well.Migration: If you want to preserve the old behavior, you can use
NodePath#shouldSkipto check whether a NodePath has been skipped before callingNodePath#requeue(). -
Remove methods starting with
_fromScopeandNodePath(#16504, #16705)// NodePath.prototype
_assertUnremoved
_call
_callRemovalHooks
_containerInsert
_containerInsertAfter
_containerInsertBefore
_getKey
_getPattern
_getQueueContexts
_getTypeAnnotation
_markRemoved
_remove
_removeFromScope
_replaceWith
_resolve
_resyncKey
_resyncList
_resyncParent
_resyncRemoved
_verifyNodeList
// Scope.prototype
_renameFromMap
_generateUidThese methods are meant to be private so there is no real migration approach. If your plugin / build is broken by this change, feel free to open an issue and tell us how you use these methods and we can see what we can do after Babel 8 is released.
@babel/eslint-plugin
-
Remove the
defaultproperty of the exports object (#14180)Migration: This change has no effect if you are using the plugin in your ESLint config. However, if you are extending
@babel/eslint-plugin, ensure that you obtain exports fromrequire("@babel/eslint-plugin")rather thanrequire("@babel/eslint-plugin").default.my-eslint-plugin.cjs// Don't add `.default` after `require()`
const { rules, rulesConfig } = require("@babel/eslint-plugin")
@babel/compat-data
-
Rename stage 4 plugin entries from
proposal-*totransform-*inplugins.json(#14976)This change also affects the
isRequiredfunction of@babel/helper-compilation-targets, which receives plugin names as its first parameter.Migration: For example, use
transform-class-propertiesrather thanproposal-class-properties. For a complete list of renamed plugin, see Packages Renames section of Babel 8 migration.my-babel-plugin.jsmodule.exports = api => {
const targets = api.targets();
// The targets have native optional chaining support
// if `transform-optional-chaining` is _not_ required
const optionalChainingSupported = !isRequired(
- "proposal-optional-chaining",
+ "transform-optional-chaining",
targets
);
}; -
Directly export data as JSON files (#17267)
The entrypoints of the package are now JSON files, rather than JS files.
Migration: If you are importing this package from ESM, you will need to change your imports adding
with { type: "json" }to them.
-
Remove
ios_saffromdata/native-modules.json(#15068)Migration: Use
iosinstead.
@babel/helper-replace-supers
-
Remove named export
environmentVisitor(#15550)Migration: Import it from
@babel/helper-environment-visitor.- import { environmentVisitor } from "@babel/helper-replace-supers";
+ import environmentVisitor from `@babel/helper-environment-visitor`; -
Remove named export
skipAllButComputedKey(#15550)Migration: Use
requeueComputedKeyAndDecoratorsinstead. Find and replace the following import and usagemy-babel7-plugin.jsimport { skipAllButComputedKey } from "@babel/helper-replace-supers";
skipAllButComputedKey(path);to
my-babel8-plugin.jsimport { requeueComputedKeyAndDecorators } from `@babel/helper-environment-visitor`;
path.skip();
requeueComputedKeyAndDecorators(path);
@babel/helper-simple-access
-
Remove the the third parameter
includeUpdateExpressionfrom the default export (#15550)Note that the Babel 8 behavior is the same as the default Babel 7 behavior (i.e.
includeUpdateExpression: true).
@babel/highlight
-
Remove the
getChalkfunction (https://github.com/babel/babel/pull/15812)If you need to use
chalk, add it to your dependencies.
Plugin API changes
-
Remove
getModuleNamefrom plugin pass (#12724)Migration: Use
.file.getModuleNameinstead.my-babel-plugin.jsmodule.exports = {
name: "my-babel-plugin",
visitor: {
Identifier(path, pass) {
- const moduleName = pass.getModuleName();
+ const moduleName = pass.file.getModuleName();
}
}
}
-
Remove
addImportfrom plugin pass (#15576)This change probably will not affect your plugin as this method is already throwing an error in Babel 7.
Migration: Use
addNamedoraddDefaultfrom@babel/helper-module-importsinstead. -
Stop supporting plugin fields as named exports (#15576)
For example, the following file is not a valid plugin anymore:
legacy-babel-plugin.jsexport const name = "legacy-babel-plugin";
export const visitor = {
Identifier() {}
}Migration: Find such patterns and use a default export instead, either exporting a plugin object or a factory function.
my-babel-plugin.cjsexport default {
name: "babel-plugin",
visitor: {
Identifier() {}
}
}