Unofficial TypeScript Syntax and Runtime Semantics

About this Specification

The document at https://qnighy.github.io/ts-syntax-spec/ is the most accurate and up-to-date version of this specification. It contains the content of the most recently published snapshot plus any modifications that will be included in the next snapshot.

Contributing to this Specification

This specification is developed on GitHub. There are a number of ways to contribute to the development of this specification:

Refer to the colophon for more information on how this document is created.

Copyright & Software License

Copyright © 2026 Ecma International (for the parts of this specification derived from ECMA-262).

Copyright © 2026 Masaki Hara and contributors.

This specification is licensed under the MIT License.

Introduction

This document provides an unofficial specification for the syntax and runtime semantics of TypeScript, describing TypeScript as a syntactic extension to ECMAScript as defined in ECMA-262.

TypeScript extends ECMAScript with type annotations, type declarations, and a small number of additional expression and statement forms. This specification aims to precisely define the syntax of these extensions and, where applicable, their runtime semantics (typically type erasure).

This is not an official specification endorsed by Microsoft or any standards body. It is a community effort to document TypeScript's syntax in a format compatible with ECMA-262's conventions.

1 Scope

This specification defines the syntax and runtime semantics of TypeScript as an extension to ECMAScript, as defined by ECMA-262. It covers type annotation syntax, type declaration syntax, and additional expression and statement forms introduced by TypeScript.

2 Conformance

The features described in this specifications are classified into the following categories:

An implementation supporting both TypeScript and JSX doesn't automatically support TSX.

An implementation must first conform to ECMA-262 as described in the original spec's conformance requirements. As an exception, Forbidden Extensions is modified in subclause 14.1 to allow type annotations without interfering with the original spec's forward compatibility intent.

To conform to this specification, an implementation must support some or all of the categories as well as ECMA-262's conformance requirements, and clearly document which categories are supported.

Note

This "conformance" is what the conformance requirements would be if this specification were an authoritative standard.

In reality, there is no authority for this specification to enforce conformance.

2.1 TypeScript Syntax Conformance

If an implementation supports TypeScript syntax, it must be able to parse a source using a Syntax Context Record whose [[TypeScript]] is true and its [[JSX]] is false.

2.2 JSX Syntax Conformance

If an implementation supports JSX syntax, it must be able to parse a source using a Syntax Context Record whose [[TypeScript]] is false and its [[JSX]] is true.

2.3 JSX Semantics Conformance

JSX semantics is highly dependent on user configuration, such as Babel config. Hence, we assume that additional custom static analysis is performed to fully fulfill UI frameworks' needs.

As such, this specification only describes a base semantics that a custom transpiler plugin works on.

A conforming implementation supporting JSX must document the values of syntax context properties it uses for interpreting JSX syntax, and additional transformation applied to JSX constructs.

Note

For example, in React Automatic JSX Runtime, if an attribute named key precedes any spread attributes in the element, the key attribute is evaluated after all the other attributes.

This is a React-specific transformation not documented normatively in this specification.

2.4 TSX Syntax Conformance

If an implementation supports TSX syntax, it must be able to parse a source using a Syntax Context Record whose [[TypeScript]] is true and its [[JSX]] is true, in addition to supporting both TypeScript and JSX syntax individually.

TSX does not have its own subfeatures; an implementation supporting TSX must consistently support subfeatures for TypeScript and JSX in TSX mode as well.

3 References

The following documents are referred to in the text in such a way that some or all of their content constitutes requirements of this document. For dated references, only the edition cited applies. For undated references, the latest edition of the referenced document (including any amendments) applies.

3.1 Normative References

ECMA-262, ECMAScript® Language Specification.
https://tc39.es/ecma262/

3.2 Informative References

TypeScript Documentation.
https://www.typescriptlang.org/docs/

4 Notational Conventions

This specification follows the same notational conventions as defined by ECMA-262 (Notational conventions).

4.1 Grammar Notation

This specification follows the same grammar notation convention as defined by ECMA-262 (Grammar Notation), including grammatical parameters and lookahead restrictions. Grammar productions in this specification extend those defined in ECMA-262.

4.2 Backtracking over cover grammars

ECMAScript and TypeScript, despite their compatibility, have totally different principles for their grammar:

  • The ECMAScript spec and its implementations are developed in mutual cooperation, while in TypeScript, TSC functions as the de facto reference implementation, and the other implementations follow TSC's behavior.
  • ECMAScript is intentionally kept LR(1) with a few extensions, while TypeScript syntax can have unbounded lookahead.

To accommodate this difference, this specification is written intentionally in a different style to describe grammar constructs that require explicit disambiguation.

4.3 Syntax Context

Behavior of TypeScript programs depends on how the implementation is configured. To formalize its interface, this specification introduces the concept of syntax context attached to a source text being parsed.

When a TypeScript source text is being matched against a goal symbol, the specification requires the caller of the parsing algorithm to provide a syntax context, which is a syntax context record.

The current syntax context is defined as follows:

Some nonterminals define syntax alterations. They are like conditionals [+Await] / [~Await] but is matched against the current syntax context.

When a syntax context is not provided, the default Syntax Context Record is used.

4.4 Syntax Mapping

For simplicity, this specification reuses ECMAScript's Syntax-Directed Operations even when the production in question is modified from the original grammar.

A production in this specification may be mapped to a production in ECMA-262. In such cases, the syntax-directed operations of the said production in this specification are derived from the syntax-directed operations of the referenced production in ECMA-262 by transforming the derivation tree as specified in the mapping. The transformation can be omitted if the original production can be uniquely reconstructed from the modified production by removing some symbols in the modified production.

This specification may override some of the derived syntax-directed operations, as it does for ones derived for chain productions.

For example, if the following production:

FunctionRestParameter[Yield, Await] : BindingRestElement[?Yield, ?Await] ?opt TypeAnnotation[?Yield, ?Await]opt

is mapped to the following production in ECMA-262:

FunctionRestParameter[Yield, Await] : BindingRestElement[?Yield, ?Await]

Then the transformation is uniquely determined because the only way to reconstruct the original production is by removing the two optional annotations.

BoundNames of this production is then automatically derived from the BindingElement nonterminal because the original production is a chain production.

4.5 Algorithm Conventions

This section extends ECMAScript Algorithm Conventions.

4.5.1 Syntax-Directed Operations

This section extends ECMAScript Syntax-Directed Operations.

The source text matched by a grammar production or Parse Node derived from it is extended as follows:

Note

For example, ((): number => 0).toString() typically yields "() => 0".

5 TypeScript Data Types and Values

This section extends ECMAScript Data Types and Values.

5.1 TypeScript Specification Types

This section extends ECMAScript Specification Types.

5.1.1 The Syntax Context Record Specification Type

The Syntax Context Record type is used to represent the configuration of the parser that affects syntaxes added in this specification.

Table 1: Syntax Context Record Fields
Field Name Value Meaning
[[TypeScript]] a Boolean Indicates whether the parser is currently parsing TypeScript syntax.
[[JSX]] a Boolean Indicates whether the parser is currently parsing JSX syntax.
[[JSXLazy]] a Boolean Indicates whether evaluation of expressions in JSX elements should be deferred until necessary.

A Syntax Context Record may have additional implementation-defined fields to be used in the implementation-defined parts of the following abstract operations.

Note

[[JSXLazy]] is intended to represent the "DOM Expressions" semantics, which is primarily used by Solid.

The default Syntax Context Record is the Syntax Context Record { [[TypeScript]]: false, [[JSX]]: false }.

5.1.1.1 IsValidJSXElement ( ctx, skel )

The abstract operation IsValidJSXElement takes arguments ctx (a Syntax Context Record) and skel (a JSX Element Skeleton Record or a JSX Fragment Skeleton Record) and returns a Boolean. It performs the following steps when called:

  1. If ctx.[[JSX]] is false, return false.
  2. Return true or false based on ctx and skel in an implementation-defined manner.
Note

This is a UI framework-specific hook to rule out specific JSX constructs.

For example, React rejects JSXNamespacedName, as well as spread operators in JSXChild.

5.1.1.2 EvaluateJSXElement ( ctx, jsx )

The abstract operation EvaluateJSXElement takes arguments ctx (a Syntax Context Record) and jsx (a JSX Element Record or a JSX Fragment Record) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. Assert: ctx.[[JSX]] is true.
  2. Return a normal completion containing an ECMAScript language value or a throw completion based on ctx and jsx in an implementation-defined manner.
Note

In React, the list of children of jsx value goes through additional modifications before being passed to React.createElement, jsx, or jsxs.

5.1.2 JSX Skeleton Records

The JSX Skeleton Record types are used to represent the structure of JSX elements in a way that can be statically processed by syntax-directed operations.

A JSX Child Skeleton Value is a value that can appear as a child of a JSX element or fragment. It is one of the following:

A JSX Attribute Skeleton Value is spread or a JSX Attribute Skeleton Record.

5.1.2.1 JSX Element Skeleton Record

The JSX Element Skeleton Record type is a JSX Skeleton Record type representing a JSX element. It is used as the return type of JSXSkeleton for JSXElement and JSXSelfClosingElement.

Table 2: JSX Element Skeleton Record Fields
Field Name Value Meaning
[[ElementName]] a String or opaque Represents the name of the JSX element.
[[Attributes]] a list of JSX Attribute Skeleton Values Represents the attributes of the JSX element.
[[Children]] a list of JSX Child Skeleton Values Represents the children of the JSX element.

5.1.2.2 JSX Fragment Skeleton Record

The JSX Fragment Skeleton Record type is a JSX Skeleton Record type representing a JSX fragment. It is used as the return type of JSXSkeleton for JSXFragment.

Table 3: JSX Fragment Skeleton Record Fields
Field Name Value Meaning
[[Children]] a list of JSX Child Skeleton Values Represents the children of the JSX fragment.

5.1.2.3 JSX Attribute Skeleton Record

The JSX Attribute Skeleton Record type is a JSX Skeleton Record type representing a JSX attribute. It is used as the value type of attributes in the [[Attributes]] field of a JSX Element Skeleton Record.

Table 4: JSX Attribute Skeleton Record Fields
Field Name Value Meaning
[[AttributeName]] a String Represents the name of the JSX attribute.
[[AttributeValue]] a String, true, a JSX Element Skeleton Record, a JSX Fragment Skeleton Record, or opaque Represents the value of the JSX attribute. It is true if the attribute does not have an initializer.

5.1.3 JSX Records

The JSX Record types are used to represent the structure of JSX elements in a way that can be dynamically processed by Evaluation of JSX-related expressions.

A JSX Child Value is a value that can appear as a child of a JSX element or fragment. It is one of the following:

A JSX Attribute Value is a JSX Spread Attribute Record or a JSX Attribute Record.

5.1.3.1 JSX Element Record

The JSX Element Record type is a JSX Record type representing a JSX element. It is used as the return type of JSXPreEvaluation of JSXElement and JSXSelfClosingElement.

Table 5: JSX Element Record Fields
Field Name Value Meaning
[[ElementName]] a String or a JSX Element Name Expression Record Represents the name of the JSX element.
[[Attributes]] a list of JSX Attribute Values Represents the attributes of the JSX element.
[[Children]] a list of JSX Child Values Represents the children of the JSX element.

5.1.3.2 JSX Element Name Expression Record

The JSX Element Name Expression Record type is a JSX Record type representing a JSX element name that is an expression. It is used as the value of [[ElementName]] in a JSX Element Record when the element name is an expression.

Table 6: JSX Element Name Expression Record Fields
Field Name Value Meaning
[[Value]] an ECMAScript language value Represents the result of evaluating the expression of the element name.

5.1.3.3 JSX Fragment Record

The JSX Fragment Record type is a JSX Record type representing a JSX fragment. It is used as the return type of JSXPreEvaluation of JSXFragment.

Table 7: JSX Fragment Record Fields
Field Name Value Meaning
[[Children]] a list of JSX Child Values Represents the children of the JSX fragment.

5.1.3.4 JSX Attribute Record

The JSX Attribute Record type is a JSX Record type representing a JSX attribute. It is used as the value type of attributes in the [[Attributes]] field of a JSX Element Record.

Table 8: JSX Attribute Record Fields
Field Name Value Meaning
[[AttributeName]] a String Represents the name of the JSX attribute.
[[AttributeValue]] a String, true, a JSX Element Record, a JSX Fragment Record, or a JSX Attribute Expression Record Represents the value of the JSX attribute. It is true if the attribute does not have an initializer.

5.1.3.5 JSX Attribute Expression Record

The JSX Attribute Expression Record type is a JSX Record type representing a JSX attribute whose value is an expression. It is used as the value of [[AttributeValue]] in a JSX Attribute Record when the attribute value is an expression.

Table 9: JSX Attribute Expression Record Fields
Field Name Value Meaning
[[Value]] an ECMAScript language value Represents the result of evaluating the expression of the attribute value.
[[Lazy]] a Boolean If true, [[Value]] is a function object that actually evaluates the expression when called.

5.1.3.6 JSX Spread Attribute Record

The JSX Spread Attribute Record type is a JSX Record type representing a spread attribute in JSX. It is used as the value type of attributes in the [[Attributes]] field of a JSX Element Record when the attribute is a spread attribute.

Table 10: JSX Spread Attribute Record Fields
Field Name Value Meaning
[[Value]] an ECMAScript language value Represents the result of evaluating the expression of the spread attribute.
[[Lazy]] a Boolean If true, [[Value]] is a function object that actually evaluates the expression when called.

5.1.3.7 JSX Child Expression Record

The JSX Child Expression Record type is a JSX Record type representing a child of a JSX element or fragment that is an expression. It is used as the value of a child in the [[Children]] field of a JSX Element Record or a JSX Fragment Record when the child is an expression.

Table 11: JSX Child Expression Record Fields
Field Name Value Meaning
[[Value]] an ECMAScript language value Represents the result of evaluating the expression of the child.
[[Lazy]] a Boolean If true, [[Value]] is a function object that actually evaluates the expression when called.

5.1.3.8 JSX Children Spread Expression Record

The JSX Children Spread Expression Record type is a JSX Record type representing a spread child in JSX. It is used as the value of a child in the [[Children]] field of a JSX Element Record or a JSX Fragment Record when the child is a spread child.

Table 12: JSX Children Spread Expression Record Fields
Field Name Value Meaning
[[Value]] an ECMAScript language value Represents the result of evaluating the expression of the spread child.
[[Lazy]] a Boolean If true, [[Value]] is a function object that actually evaluates the expression when called.

6 Terms and Definitions

For the purposes of this document, the following terms and definitions apply.

type erasure

the process of removing type annotations and type-only declarations from TypeScript source code, producing valid ECMAScript source code.

type annotation

a syntactic construct that specifies the type of a variable, parameter, return value, or other declaration, and which is removed during type erasure.

TSC

The TypeScript Compiler, the official TypeScript implementation developed by Microsoft.

6.1 Definition of "TypeScript"

The term "TypeScript" is a trademark of Microsoft Corporation and is primarily used in the following two senses:

  1. The compiler and associated toolchain developed by Microsoft.
  2. The programming language understood by said compiler.

This community specification aims to clarify the syntax and runtime semantics of the programming language mentioned in 2. However, this entails the following two challenges:

  • The TypeScript compiler itself does not clearly define the scope of syntactically correct TypeScript. The TypeScript compiler's parser is designed to be highly permissive, and many errors generally considered syntactic are deferred until type checking. Furthermore, the type checker does not clearly distinguish between syntax errors and type errors.
  • Parsers that understand TypeScript other than the TypeScript compiler do clarify the scope of syntax errors, but they often behave inconsistently with the TypeScript compiler in edge cases.
  • The TypeScript type checker contains numerous ad-hoc behaviours. Therefore, it is not realistic to write down a specification that is properly separated from the implementation.

This specification aims to overcome these difficulties and propose a provisional specification suitable as a starting point for discussions within the TypeScript community. It defines the language specification based on the following criteria:

  • It does not define specifications that depend on type checking, focusing only on syntax and runtime semantics.
  • Among the errors output by the TypeScript type checker, those recognized as syntactic are classified as syntax errors. As a criterion for this, definitions with a level of complexity equivalent to ECMAScript syntax or Early Errors are considered syntactic.
  • It also refers to the behaviour of third-party TypeScript parsers. In cases where there are discrepancies with the TypeScript compiler, it selects the more rational specification and provides supplements regarding known differences.

It should be noted that the TypeScript language defined in this specification is unofficial and arbitrary, and possesses no binding force or authority.

7 Syntax-Directed Operations

This section extends Syntax-Directed Operations from ECMAScript.

In addition to those defined in this section, specialized syntax-directed operations are defined throughout this specification.

7.1 Evaluation

This specification extends Evaluation from ECMAScript.

See each grammar production for details.

7.2 Function Name Inference

7.2.1 Static Semantics: HasName

This section extends HasName from ECMAScript.

MemberExpression : MemberExpression ! MemberExpression ExpressionTypeArguments
  1. Return HasName of the derived MemberExpression.
UnaryExpression : < Type > UnaryExpression
  1. Return HasName of the derived UnaryExpression.
RelationalExpression : RelationalExpression as Type RelationalExpression satisfies Type
  1. Return HasName of the derived RelationalExpression.

7.2.2 Static Semantics: IsFunctionDefinition

This section extends IsFunctionDefinition from ECMAScript.

PrimaryExpression : JSXElement JSXFragment
  1. Return false.
MemberExpression : MemberExpression ! MemberExpression ExpressionTypeArguments
  1. Return IsFunctionDefinition of the derived MemberExpression.
UnaryExpression : < Type > UnaryExpression
  1. Return IsFunctionDefinition of the derived UnaryExpression.
RelationalExpression : RelationalExpression as Type RelationalExpression satisfies Type
  1. Return IsFunctionDefinition of the derived RelationalExpression.

7.2.3 Static Semantics: IsIdentifierRef

This section extends IsIdentifierRef from ECMAScript.

PrimaryExpression : JSXElement JSXFragment
  1. Return false.
MemberExpression : MemberExpression ! MemberExpression ExpressionTypeArguments
  1. Return IsIdentifierRef of the derived MemberExpression.
CallExpression : CallExpression ! CallExpression ExpressionTypeArguments
  1. Return IsIdentifierRef of the derived CallExpression.
UnaryExpression : < Type > UnaryExpression
  1. Return IsIdentifierRef of the derived UnaryExpression.
RelationalExpression : RelationalExpression as Type RelationalExpression satisfies Type
  1. Return IsIdentifierRef of the derived RelationalExpression.

7.2.4 Runtime Semantics: NamedEvaluation

This section extends NamedEvaluation from ECMAScript.

MemberExpression : MemberExpression ! MemberExpression ExpressionTypeArguments
  1. Return ? NamedEvaluation of the derived MemberExpression with argument name.
UnaryExpression : < Type > UnaryExpression
  1. Return ? NamedEvaluation of the derived UnaryExpression with argument name.
RelationalExpression : RelationalExpression as Type RelationalExpression satisfies Type
  1. Return ? NamedEvaluation of the derived RelationalExpression with argument name.

7.3 Contains

7.3.1 Static Semantics: Contains

This section extends Contains from ECMAScript.

TypeAnnotation : : Type VariableTypeAnnotation : : Type : unique symbol ReturnTypeAnnotation : : TypeOrTypePredicate TypeParameters : < TypeParameterList > < TypeParameterList , > ExpressionTypeArguments : TypeArguments Declaration : TopLevelAmbientDeclaration FunctionOverloadDeclaration
  1. Return false.
UnaryExpression : < Type > UnaryExpression
  1. Return Contains of the derived UnaryExpression.
RelationalExpression : RelationalExpression as Type RelationalExpression satisfies Type
  1. Return Contains of the derived RelationalExpression.
Note

Contains is used in the original specification to find disallowed uses of await, yield, and super expressions.

We have modified Contains to exclude type-only syntax from these rules.

Although arbitrary expressions typically do not appear in these syntaxes, they may be called recursively as Expressions in certain cases, such as through ComputedPropertyName in an ObjectLiteralType or default parameters in an AmbientFunctionDeclaration.

7.4 JSX Syntax-Directed Operations

7.4.1 Static Semantics: JSXSkeleton

The syntax-directed operation JSXSkeleton takes no arguments and returns a JSX Skeleton Record, a String, true, opaque, spread, empty, or a list of these.

Note

The caller must not rely on object identity or modify the returned JSX Skeleton Record in an observable way.

It is defined piecewise over the following productions:

JSXElement : JSXOpeningElement JSXChildrenopt JSXClosingElement
  1. Let skel be JSXSkeleton of JSXOpeningElement.
  2. Assert: skel is a JSX Element Skeleton Record.
  3. Let children be an empty list.
  4. If JSXChildren is present, then
    1. Set children to JSXSkeleton of JSXChildren.
    2. Assert: children is a list of JSX Child Skeleton Values.
  5. Set skel to a copy of skel with its [[Children]] field set to children.
  6. Return skel.
JSXFragment : < > JSXChildrenopt < / >
  1. Let children be an empty list.
  2. If JSXChildren is present, then
    1. Set children to JSXSkeleton of JSXChildren.
    2. Assert: children is a list of JSX Child Skeleton Values.
  3. Return a JSX Fragment Skeleton Record { [[Children]]: children }.
JSXSelfClosingElement : < JSXElementName TypeArgumentsopt JSXAttributesopt / > JSXOpeningElement : < JSXElementName TypeArgumentsopt JSXAttributesopt >
  1. Let name be JSXSkeleton of JSXElementName.
  2. Let attributes be an empty list.
  3. If JSXAttributes is present, then
    1. Set attributes to JSXSkeleton of JSXAttributes.
    2. Assert: attributes is a list of JSX Attribute Skeleton Values.
  4. Return a JSX Element Skeleton Record { [[Name]]: name, [[Attributes]]: attributes, [[Children]]: an empty list }.
JSXElementName : JSXLiteralIdentifier JSXNamespacedName
  1. Let nameText be StringValue of JSXElementName.
  2. Assert: nameText is a String.
  3. Return nameText.
JSXElementName : JSXSimpleIdentifier JSXThis JSXMemberExpression
  1. Return opaque.
JSXAttributes : JSXAttributes JSXAttributeListElement
  1. Let attributes be JSXSkeleton of the derived JSXAttributes.
  2. Assert: attributes is a list of JSX Attribute Skeleton Values.
  3. Let attribute be JSXSkeleton of JSXAttributeListElement.
  4. Assert: attribute is a JSX Attribute Skeleton Value.
  5. Return the list-concatenation of attributes and « attribute ».
JSXSpreadAttribute : { ... AssignmentExpression }
  1. Return spread.
JSXAttribute : JSXAttributeName JSXAttributeInitializeropt
  1. Let name be StringValue of JSXAttributeName.
  2. Assert: name is a String.
  3. Let value be true.
  4. If JSXAttributeInitializer is present, then
    1. Set value to JSXSkeleton of JSXAttributeInitializer.
    2. Assert: value is a String, a JSX Element Skeleton Record, a JSX Fragment Skeleton Record, or opaque.
  5. Return a JSX Attribute Skeleton Record { [[AttributeName]]: name, [[AttributeValue]]: value }.
JSXAttributeValue : JSXStringLiteral
  1. Let valueText be StringValue of JSXStringLiteral.
  2. Assert: valueText is a String.
  3. Return valueText.
JSXAttributeValue : { AssignmentExpression }
  1. Return opaque.
JSXChildren : JSXChildren JSXChild
  1. Let children be JSXSkeleton of the derived JSXChildren.
  2. Assert: children is a list of JSX Child Skeleton Values.
  3. Let child be JSXSkeleton of JSXChild.
  4. If child is empty, then
    1. Return children.
  5. Assert: child is a JSX Child Skeleton Value.
  6. Return the list-concatenation of children and « child ».
JSXChild : JSXText
  1. Let text be StringValue of JSXText.
  2. Assert: text is a String.
  3. Return text.
JSXChild : { }
  1. Return empty.
JSXChild : { AssignmentExpression }
  1. Return opaque.
JSXChild : { ... AssignmentExpression }
  1. Return spread.

7.4.2 Runtime Semantics: JSXPreEvaluation

The syntax-directed operation JSXPreEvaluation takes no arguments and returns a Completion Record. It is defined piecewise over the following productions:

JSXElement : JSXOpeningElement JSXChildrenopt JSXClosingElement
  1. Let elem be ? JSXPreEvaluation of JSXOpeningElement.
  2. Assert: elem is a JSX Element Record.
  3. Let children be an empty list.
  4. If JSXChildren is present, then
    1. Set children to ? JSXPreEvaluation of JSXChildren.
    2. Assert: children is a list of JSX Child Values.
  5. Set elem to a copy of elem with its [[Children]] field set to children.
  6. Return elem.
JSXFragment : < > JSXChildrenopt < / >
  1. Let children be an empty list.
  2. If JSXChildren is present, then
    1. Set children to ? JSXPreEvaluation of JSXChildren.
    2. Assert: children is a list of JSX Child Values.
  3. Return a JSX Fragment Record { [[Children]]: children }.
JSXSelfClosingElement : < JSXElementName TypeArgumentsopt JSXAttributesopt / > JSXOpeningElement : < JSXElementName TypeArgumentsopt JSXAttributesopt >
  1. Let name be ? JSXPreEvaluation of JSXElementName.
  2. Assert: name is a String.
  3. Let attributes be an empty list.
  4. If JSXAttributes is present, then
    1. Set attributes to ? JSXPreEvaluation of JSXAttributes.
    2. Assert: attributes is a list of JSX Attribute Values.
  5. Return a JSX Element Record { [[Name]]: name, [[Attributes]]: attributes, [[Children]]: an empty list }.
JSXElementName : JSXLiteralIdentifier JSXNamespacedName
  1. Let nameText be StringValue of JSXElementName.
  2. Assert: nameText is a String.
  3. Return nameText.
JSXElementName : JSXSimpleIdentifier JSXThis JSXMemberExpression
  1. Let value be ? Evaluation of JSXElementName.
  2. Return a JSX Element Name Expression Record { [[Value]]: value }.
JSXAttributes : JSXAttributes JSXAttributeListElement
  1. Let attributes be ? JSXPreEvaluation of the derived JSXAttributes.
  2. Assert: attributes is a list of JSX Attribute Values.
  3. Let attribute be ? JSXPreEvaluation of JSXAttributeListElement.
  4. Assert: attribute is a JSX Attribute Value.
  5. Return the list-concatenation of attributes and « attribute ».
JSXSpreadAttribute : { ... AssignmentExpression }
  1. Let ctx be the current syntax context.
  2. If ctx.[[JSXLazy]] is true, then
    1. Let thunk be CreateThunk(AssignmentExpression).
    2. Return a JSX Spread Attribute Record { [[Value]]: thunk, [[Lazy]]: true }.
  3. Let value be ? Evaluation of AssignmentExpression.
  4. Return a JSX Spread Attribute Record { [[Value]]: value, [[Lazy]]: false }.
JSXAttribute : JSXAttributeName JSXAttributeInitializeropt
  1. Let name be StringValue of JSXAttributeName.
  2. Assert: name is a String.
  3. Let value be true.
  4. If JSXAttributeInitializer is present, then
    1. Set value to ? JSXPreEvaluation of JSXAttributeInitializer.
    2. Assert: value is a String, a JSX Element Record, a JSX Fragment Record, or a JSX Attribute Expression Record.
  5. Return a JSX Attribute Record { [[Name]]: name, [[Value]]: value }.
JSXAttributeValue : JSXStringLiteral
  1. Let valueText be StringValue of JSXStringLiteral.
  2. Assert: valueText is a String.
  3. Return valueText.
JSXAttributeValue : { AssignmentExpression }
  1. Let ctx be the current syntax context.
  2. If ctx.[[JSXLazy]] is true, then
    1. Let thunk be CreateThunk(AssignmentExpression).
    2. Return a JSX Attribute Expression Record { [[Value]]: thunk, [[Lazy]]: true }.
  3. Let value be ? Evaluation of AssignmentExpression.
  4. Return a JSX Attribute Expression Record { [[Value]]: value, [[Lazy]]: false }.
JSXChildren : JSXChildren JSXChild
  1. Let children be an empty list.
  2. If JSXChildren is present, then
    1. Set children to ? JSXPreEvaluation of the derived JSXChildren.
    2. Assert: children is a list of JSX Child Values.
  3. Let child be ? JSXPreEvaluation of JSXChild.
  4. If child is empty, then
    1. Return children.
  5. Assert: child is a JSX Child Value.
  6. Return the list-concatenation of children and « child ».
JSXChild : JSXText
  1. Let text be StringValue of JSXText.
  2. Assert: text is a String.
  3. Return text.
JSXChild : { }
  1. Return empty.
JSXChild : { AssignmentExpression }
  1. Let ctx be the current syntax context.
  2. If ctx.[[JSXLazy]] is true, then
    1. Let thunk be CreateThunk(AssignmentExpression).
    2. Return a JSX Child Expression Record { [[Value]]: thunk, [[Lazy]]: true }.
  3. Let value be ? Evaluation of AssignmentExpression.
  4. Return a JSX Child Expression Record { [[Value]]: value, [[Lazy]]: false }.
JSXChild : { ... AssignmentExpression }
  1. Let ctx be the current syntax context.
  2. If ctx.[[JSXLazy]] is true, then
    1. Let thunk be CreateThunk(AssignmentExpression).
    2. Return a JSX Child Spread Expression Record { [[Value]]: thunk, [[Lazy]]: true }.
  3. Let value be ? Evaluation of AssignmentExpression.
  4. Return a JSX Child Spread Expression Record { [[Value]]: value, [[Lazy]]: false }.

7.4.3 CreateThunk ( expr )

The abstract operation CreateThunk takes argument expr (an AssignmentExpression node) and returns an ECMAScript language value. It performs the following steps when called:

  1. Let env be the LexicalEnvironment of the running execution context.
  2. Let privateEnv be the running execution context's PrivateEnvironment.
  3. Let parameters be a synthetic ArrowParameters node containing no parameters.
  4. Let body be a synthetic ConciseBody node containing expr or expr wrapped by ( and ) if expr starts with {.
  5. Let funcNode be a synthetic ArrowFunction node by concatenating parameters, =>, and body.
  6. Let sourceText be the source text matched by funcNode.
  7. Let closure be OrdinaryFunctionCreate(%Function.prototype%, sourceText, parameters, body, lexical-this, env, privateEnv).
  8. Perform SetFunctionName(closure, "").
  9. Return closure.

7.5 Miscellaneous

7.5.1 Static Semantics: AssignmentTargetType

This section extends AssignmentTargetType from ECMAScript.

PrimaryExpression : JSXElement JSXFragment MemberExpression : MemberExpression ExpressionTypeArguments CallExpression : CallExpression ExpressionTypeArguments
  1. Return invalid.
MemberExpression : MemberExpression !
  1. Return AssignmentTargetType of the derived MemberExpression.
CallExpression : CallExpression !
  1. Return AssignmentTargetType of the derived CallExpression.
UnaryExpression : < Type > UnaryExpression
  1. Return AssignmentTargetType of the derived UnaryExpression.
RelationalExpression : RelationalExpression as Type RelationalExpression satisfies Type
  1. Return AssignmentTargetType of the derived RelationalExpression.
Note 1

x! = e, (<T>x) = e, (x as T) = e, (x satisfies T) = e are valid according to these rules.

Note 2

Actual parsers implement these rules in various ways.

  • SWC also allows x<T> = e.

8 TypeScript Language: Lexical Grammar

TypeScript's lexical grammar is largely identical to ECMAScript's lexical grammar, with the following extensions:

8.1 Rescanning of < and >

The following productions use < and > as angle brackets:

TypeParameters : < TypeParameterList > < TypeParameterList , > TypeArguments : < TypeArgumentList > < TypeArgumentList , > UnaryExpression : < Type > UnaryExpression

Additionally, the following grammar is used for lookahead to detect type arguments:

DoesNotFollowTypeArgumentsNLT : import < < > DoesNotFollowTypeArgumentsLT : < >

When < or > in such productions is expected, the parser needs to rescan the following tokens to correctly interpret them as angle brackets:

  • <<
  • >>
  • >>>
  • >>=
  • >=
Note 1

<= and <<= do not involve rescanning, as they cannot be reinterpreted as part of valid TypeScript syntax.

Note 2

The following examples illustrate the need for rescanning:

  • In type T = Readonly<Partial<U>>;, the token >> is split into two tokens.
  • In type T = Readonly<Partial<Omit<U, keyof V>>>;, the token >>> is split into three tokens.
  • In type T<U>= V;, the token >= is split into two tokens.
  • In type T<K extends Exclude<keyof U, keyof V>>= W;, the token >>= is split into three tokens.
  • In f<<T>() => void>();, the token << is split into two tokens.
Note 3

It is possible to implement the rescanning inversely, first tokenizing them as one-letter tokens and then combining them as needed. TSC does this for >.

8.2 JSX Tokens

8.2.1 JSX Identifier Names

Where JSXIdentifierName is allowed as the next token, the following goal is used instead of InputElementDiv or relevant tokenization goals.

InputElementJSXIdentifier :: WhiteSpace LineTerminator Comment JSXIdentifierName { < > / . : = Note 1

The possible occurrences of this goal are:

Typically you can tokenize InputElementDiv except when IdentifierName is found, you need to rescan it as JSXIdentifierName.

JSXIdentifierName :: JSXIdentifierStart JSXIdentifierName JSXIdentifierPart JSXIdentifierStart :: IdentifierStartChar \ UnicodeEscapeSequence JSXIdentifierPart :: JSXIdentifierPartChar \ UnicodeEscapeSequence JSXIdentifierPartChar :: IdentifierPartChar - Note 2

JSXIdentifierName is IdentifierName with the addition of the - character.

Trailing -s and consecutive -s are also allowed.

8.2.1.1 Static Semantics: Early Errors

JSXIdentifierStart :: \ UnicodeEscapeSequence JSXIdentifierPart :: \ UnicodeEscapeSequence Note 1

The latter implies the former. We structure the Early Errors here as such to reflect nuances in parser implementations.

The latter rule follows absence of UnicodeEscapeSequence in the original JSX spec.

Note 2

Actual parsers implement these rules in various ways.

8.2.1.2 Static Semantics: IdentifierCodePoints

The syntax-directed operation IdentifierCodePoints takes no arguments and returns a List of code points.

It extends IdentifierCodePoints.

JSXIdentifierName :: JSXIdentifierStart
  1. Let cp be the IdentifierCodePoint of JSXIdentifierStart.
  2. Return « cp ».
JSXIdentifierName :: JSXIdentifierName JSXIdentifierPart
  1. Let cps be the IdentifierCodePoints of the derived JSXIdentifierName.
  2. Let cp be the IdentifierCodePoint of JSXIdentifierPart.
  3. Return the list-concatenation of cps and « cp ».

8.2.1.3 Static Semantics: IdentifierCodePoint

The syntax-directed operation IdentifierCodePoint takes no arguments and returns a code point.

It extends IdentifierCodePoint.

JSXIdentifierPart :: JSXIdentifierPartChar
  1. Return the code point matched by JSXIdentifierPartChar.

8.2.1.4 Runtime Semantics: HasHyphen

The syntax-directed operation HasHyphen takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

JSXIdentifierName :: JSXIdentifierStart JSXIdentifierName JSXIdentifierPart
  1. Let name be the IdentifierCodePoints of this JSXIdentifierName.
  2. If name contains -, return true.
  3. Assert: this JSXIdentifierName matches IdentifierName.
  4. Return false.

8.2.1.5 Runtime Semantics: IsJSXLiteralName

The syntax-directed operation IsJSXLiteralName takes no arguments and returns a Boolean. It is defined piecewise over the following productions:

JSXIdentifierName :: JSXIdentifierStart JSXIdentifierName JSXIdentifierPart
  1. Let name be the IdentifierCodePoints of this JSXIdentifierName.
  2. Assert: name is not empty.
  3. Let nameStart be the first code point of name.
  4. If nameStart is an ASCII lowercase letter, return true.
  5. If HasHyphen of this JSXIdentifierName is true, return true.
  6. Assert: this JSXIdentifierName matches IdentifierName.
  7. Return false.
Note

Examples:

  • The tag name of <div /> is "div", a string literal, because it starts with an ASCII lowercase letter.
  • The tag name of <my-component /> is "my-component", a string literal, because it contains a -. It also starts with an ASCII lowercase letter.
  • The tag name of <My-Component /> is "My-Component", a string literal, because it contains a -.
  • The tag name of <MyComponent /> is MyComponent, an identifier, because it does not start with an ASCII lowercase letter and does not contain a -.
  • The tag name of <あ /> is , an identifier, because is not a lowercase letter.
  • The tag name of <π /> is π, an identifier. Although π is a lowercase letter, it is not a part of ASCII.
  • The tag name of <à /> depends on whether à is represented in its NFC or NFD form. In its NFC form, it is an identifier as the first code point à is not in ASCII. In its NFD form, it is a string literal as the first code point is a.

8.2.2 JSX Text Tokens

Where JSXText is allowed as the next token, the following goal is used instead of InputElementDiv or relevant tokenization goals.

InputElementJSXText :: JSXText JSXIgnoredWhiteSpace < { Note 1

The possible occurrences of this goal are:

Note the lexical goal after JSXElement and JSXFragment depends on the context where JSXElement or JSXFragment appears.

The parser must not apply usual whitespace/comment skipping rules in this context. The tokenization rule is totally different here from other contexts.

Note 2

TSC and SWC tokenizes </ here in addition. See note in JSX Elements and Fragments.

For this goal, JSXIgnoredWhiteSpace is discarded, except when it appears as part of JSXText.

Unlike ordinary tokenization goals, this goal does not have WhiteSpace, LineTerminator, or Comment. They are not skipped like in other places.

The following nonterminals are defined for use in this goal:

JSXText :: JSXIgnoredWhiteSpaceopt JSXTextBody JSXIgnoredWhiteSpaceopt JSXVerbatimWhiteSpace JSXTextBodyopt JSXIgnoredWhiteSpaceopt JSXTextBody :: JSXTextChar JSXTextBody JSXTextChar JSXTextBody JSXVerbatimWhiteSpace JSXTextBody JSXCollapsingWhiteSpace JSXTextChar JSXTextChar :: JSXLiteralChar JSXCharacterReference [lookahead ≠ JSXCharacterReference] & JSXLiteralChar :: SourceCharacter but not one of < or > or { or } or & or WhiteSpace or LineTerminator JSXCharacterReference :: & JSXNamedCharacterReferenceName ; &# JSXCodePoint ; JSXCodePoint :: DecimalDigits[~Sep] but only if the MV of DecimalDigits ≤ 0x10FFFF x HexDigits[~Sep] but only if the MV of HexDigits ≤ 0x10FFFF JSXVerbatimWhiteSpace :: JSXInlineWhiteSpace [lookahead ∉ { WhiteSpace, LineTerminator }] JSXCollapsingWhiteSpace :: JSXMultilineWhiteSpace [lookahead ∉ { WhiteSpace, LineTerminator }] JSXIgnoredWhiteSpace :: JSXMultilineWhiteSpace [lookahead ∉ { WhiteSpace, LineTerminator }] JSXInlineWhiteSpace :: WhiteSpace JSXInlineWhiteSpace WhiteSpace JSXMultilineWhiteSpace :: JSXInlineWhiteSpace LineTerminator JSXMultilineWhiteSpace WhiteSpace JSXMultilineWhiteSpace LineTerminator Note 3

JSX Text is the longest sequence terminated by a { or <, and interpreted as follows:

  • A sequence of white space characters and/or line terminators is interpreted as follows:
    • If it does not contain line terminators, it is interpreted verbatim.
    • If it contains line terminators, and it is surrounded by non-white-space characters, it is collapsed to a single space.
    • If it contains line terminators, and it appears at the start or end of the JSX text, it is ignored.
  • A full HTML character reference is interpreted as the corresponding Unicode code point.
  • An & that does not start a valid character reference is interpreted as a literal &.
  • All other characters are interpreted as literal characters.

JavaScript comments or JavaScript string escapes are not interpreted within JSX text.

Note 4

Actual parsers implement these rules in various ways.

8.2.2.1 Static Semantics: SV

SV is extended as follows:

8.2.3 JSX Strings

Where JSXStringLiteral is allowed as the next token, the following goal is used instead of InputElementDiv or relevant tokenization goals.

InputElementJSXString :: WhiteSpace LineTerminator Comment JSXStringLiteral { < Note 1

As usual, WhiteSpace, LineTerminator, and Comment are discarded.

Note 2

Typically you can tokenize InputElementDiv except StringLiteral is replaced with JSXStringLiteral.

Note 3

The only occurrence of this goal is after = in JSXAttributeInitializer.

JSXStringLiteral :: " JSXDoubleStringCharactersopt " ' JSXSingleStringCharactersopt ' JSXDoubleStringCharacters :: JSXDoubleStringCharacter JSXDoubleStringCharactersopt JSXSingleStringCharacters :: JSXSingleStringCharacter JSXSingleStringCharactersopt JSXDoubleStringCharacter :: SourceCharacter but not one of " or & JSXCharacterReference [lookahead ≠ JSXCharacterReference] & JSXSingleStringCharacter :: SourceCharacter but not one of ' or & JSXCharacterReference [lookahead ≠ JSXCharacterReference] & Note 4

JSX String Literals do not interpret backslash escapes or line continuations. They instead interpret character references.

Note 5

JSX String Literals allow multi-line strings and they are interpreted as it is represented in the source code. It contradicts ECMAScript's implicit contract that the three kinds of newlines in source code can be safely normalized.

8.2.3.1 Static Semantics: SV

SV is extended as follows:

8.2.4 JSX Character References

JSXCharacterReference :: & JSXNamedCharacterReferenceName ; &# JSXCodePoint ; JSXCodePoint :: DecimalDigits[~Sep] but only if the MV of DecimalDigits ≤ 0x10FFFF x HexDigits[~Sep] but only if the MV of HexDigits ≤ 0x10FFFF Note 1

There is a difference in how character references are handled in JSX compared to HTML parsing:

Unlike HTML, omission of ; in a character reference results in a verbatim interpretation of the & character.

Unlike HTML, numbered character references to C1 control characters are interpreted as they are; they are not replaced with the corresponding Windows-1252 characters.

Note 2

Actual parsers implement these rules in various ways.

  • TSC and SWC currently fails due to internal parser error when parsing JSXCodePoint that exceeds the valid Unicode range.
  • SWC currently also fails due to internal parser error when parsing JSXCodePoint that designates a surrogate code point.

8.2.4.1 Static Semantics: SV

SV is extended as follows:

8.2.4.2 Static Semantics: MV

MV is extended as follows:

9 TypeScript Language: Types

Note

Type semantics is out of scope for this specification.

9.1 Primary Types

PrimaryType[Yield, Await] : TypeReference[?Yield, ?Await] TypeQuery[?Yield, ?Await] KeywordType LiteralType ThisType TupleType[?Yield, ?Await] ObjectType[?Yield, ?Await] MappedType[?Yield, ?Await] TemplateLiteralType[?Yield, ?Await] ( Type[?Yield, ?Await] ) Note

TSC parses PrimaryType permissively as described in B.2. It implies that TSC doesn't parse the following valid expressions using < operators:

  • f < x.#y > (z), where #y is defined in the enclosing class

9.1.1 Type Identifiers

TypeIdentifierReference[Yield, Await] : IdentifierReference[?Yield, ?Await] but not ExtraKeywordType but not TypeOperator TypeNamespaceReference[Yield, Await] : IdentifierReference[?Yield, ?Await] but not TypeOperator BindingTypeIdentifier[Yield, Await] : BindingIdentifier[?Yield, ?Await] but not ExtraKeywordType TypeOperator :: one of infer keyof readonly unique Note 1

TypeIdentifierReference derives from IdentifierReference, and BindingTypeIdentifier derives from BindingIdentifier. This means that ECMAScript's usual rules apply for the following keywords:

Note 2

Actual parsers implement these rules in various ways.

  • TSC permits eval and arguments as binding type identifiers even in strict mode.
  • Babel permits escaped reserved words as type identifiers.

9.1.1.1 Static Semantics: Early Errors

TypeIdentifierReference : IdentifierReference but not ExtraKeywordType but not TypeOperator TypeNamespaceReference : IdentifierReference but not TypeOperator BindingTypeIdentifier : BindingIdentifier but not ExtraKeywordType Note

These rules are here to disallow escaped reserved words.

9.1.2 Type References

TypeReference[Yield, Await] : TypeIdentifierReference[?Yield, ?Await] TypeIdentifierReference[?Yield, ?Await] [no LineTerminator here] TypeArguments[?Yield, ?Await] QualifiedTypeName[?Yield, ?Await] QualifiedTypeName[?Yield, ?Await] [no LineTerminator here] TypeArguments[?Yield, ?Await] QualifiedTypeName[Yield, Await] : TypeImportCall QualifiedTypeName[?Yield, ?Await] . IdentifierName TypeNamespaceReference[?Yield, ?Await] . IdentifierName Note 1

Type identifiers following . is IdentifierName, therefore exempt from the restrictions on reserved words.

Note 2

TSC parses TypeReference permissively as described in B.2. It implies that TSC doesn't parse the following valid expressions using < operators:

  • f < x.#y > (z), where #y is defined in the enclosing class

9.1.3 Type Imports

TypeImportCall : import ( StringLiteral ) import ( StringLiteral , { with : WithClauseBody ,opt } ) WithClauseBody : { } { WithEntries ,opt } Note 1

WithClauseBody is WithClause but without preceding with keyword.

Note 2

Before TypeScript 6.0, assert was allowed as an alternative to the with keyword.

Note 3

TSC parses TypeImportCall permissively as described in B.2. It implies that TSC doesn't parse the following valid expressions using < operators:

  • f < import(x) > (x)
  • f < import.meta > (x)

9.1.4 Type Queries

TypeQuery[Yield, Await] : typeof ExpressionInTypeQuery[?Yield, ?Await] ExpressionInTypeQuery[Yield, Await] : IdentifierReference[?Yield, ?Await] TypeImportCall ExpressionInTypeQuery[?Yield, ?Await] . IdentifierName Note

TSC parses TypeQuery permissively as described in B.2. It implies that TSC doesn't parse the following valid expressions using < operators:

  • f < typeof x.#y > (z), where #y is defined in the enclosing class

9.1.5 Keyword Types

KeywordType : void ExtraKeywordType ExtraKeywordType :: one of any bigint boolean never number object string symbol undefined unknown Note

Parsers may need one-token lookahead to disambiguate ExtraKeywordType from TypeNamespaceReference.

9.1.6 Literal Types

LiteralType : NullLiteral BooleanLiteral StringLiteral NoSubstitutionTemplate NumericLiteral - NumericLiteral Note

It implies that legacy octal/non-octal literals and legacy octal/non-octal escapes are not allowed in strict mode.

Actual parsers implement these rules in various ways.

  • TSC disallows these legacy constructs even outside of strict mode.

9.1.6.1 Static Semantics: Early Errors

LiteralType : NoSubstitutionTemplate Note

Actual parsers implement these rules in various ways.

  • TSC permits invalid escapes in template literal types.

9.1.7 The this Type

ThisType : this

9.1.8 Tuple Types

TupleType[Yield, Await] : [ ] [ TupleTypeElements[?Yield, ?Await] ] [ TupleTypeElements[?Yield, ?Await] , ] TupleTypeElements[Yield, Await] : TupleTypeElement[?Yield, ?Await] TupleTypeElements[?Yield, ?Await] , TupleTypeElement[?Yield, ?Await] TupleTypeElement[Yield, Await] : RequiredTupleTypeElement[?Yield, ?Await] OptionalTupleTypeElement[?Yield, ?Await] TupleTypeRestElement[?Yield, ?Await] RequiredTupleTypeElement[Yield, Await] : Type[?Yield, ?Await] BindingIdentifier[?Yield, ?Await] : Type[?Yield, ?Await] OptionalTupleTypeElement[Yield, Await] : Type[?Yield, ?Await] ? BindingIdentifier[?Yield, ?Await] ? : Type[?Yield, ?Await] TupleTypeRestElement[Yield, Await] : ... Type[?Yield, ?Await] ... BindingIdentifier[?Yield, ?Await] : Type[?Yield, ?Await] Note

TSC parses TupleType permissively as described in B.2. It implies that TSC doesn't parse the following valid expressions using < operators:

  • f < [,] > (x)

9.1.8.1 Static Semantics: Early Errors

TupleTypeElements : TupleTypeElements , TupleTypeElement Note

Actual parsers implement these rules in various ways.

  • TSC restricts Type in unlabeled optional elements to PostfixType. It is because the whole element is first parsed as a JSDoc nullable type and then reinterpreted.
  • Babel permits optional elements appearing after rest elements.
  • Babel permits rest elements appearing after other rest elements.

9.1.9 Object Types

ObjectType[Yield, Await] : { } { ObjectTypeMembers[?Yield, ?Await] } { ObjectTypeMembers[?Yield, ?Await] , } { ObjectTypeMembers[?Yield, ?Await] ; } ObjectTypeMembers[Yield, Await] : ObjectTypeMember[?Yield, ?Await] , ObjectTypeMember[?Yield, ?Await] ; ObjectTypeMembers[?Yield, ?Await] , ObjectTypeMember[?Yield, ?Await] ObjectTypeMembers[?Yield, ?Await] ; ObjectTypeMember[?Yield, ?Await] ObjectTypeMember[Yield, Await] : ObjectPropertySignature[?Yield, ?Await] ObjectMethodSignature[?Yield, ?Await] ObjectGetAccessorSignature[?Yield, ?Await] ObjectSetAccessorSignature[?Yield, ?Await] ObjectCallSignature[?Yield, ?Await] ObjectConstructSignature[?Yield, ?Await] ObjectIndexSignature[?Yield, ?Await] ObjectPropertySignature[Yield, Await] : ReadonlyModifieropt PropertyName[?Yield, ?Await] ?opt TypeAnnotation[?Yield, ?Await]opt ObjectMethodSignature[Yield, Await] : ReadonlyModifieropt PropertyName[?Yield, ?Await] ?opt TypeParameters[?Yield, ?Await, +Const, ~InOut]opt ( FormalParameters[?Yield, ?Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt ObjectGetAccessorSignature[Yield, Await] : get PropertyName[?Yield, ?Await] ( ) ReturnTypeAnnotation[?Yield, ?Await, ~Predicate]opt ObjectSetAccessorSignature[Yield, Await] : set PropertyName[?Yield, ?Await] ( PropertySetParameterList ) ReturnTypeAnnotation[?Yield, ?Await, ~Predicate]opt ObjectCallSignature[Yield, Await] : TypeParameters[?Yield, ?Await, +Const, ~InOut]opt ( FormalParameters[?Yield, ?Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt ObjectConstructSignature[Yield, Await] : new TypeParameters[?Yield, ?Await, +Const, ~InOut]opt ( FormalParameters[?Yield, ?Await] ) ReturnTypeAnnotation[?Yield, ?Await, ~Predicate]opt ObjectIndexSignature[Yield, Await] : ReadonlyModifieropt [ BindingIdentifier[?Yield, ?Await] TypeAnnotation[?Yield, ?Await] ] TypeAnnotation[?Yield, ?Await]opt ReadonlyModifier : readonly [no LineTerminator here] Note

The index type in ObjectIndexSignature must resolve to a type that is a "valid index key type", but it's beyond parsers' capabilities to enforce this.

A valid index key type is

  • the string type,
  • the number type,
  • the symbol type,
  • a template literal type satisfying a specific condition,
  • a non-generic intersection containing at least one valid index key type,
  • or a union of valid index key types.

9.1.10 Mapped Types

MappedType[Yield, Await] : { ReadonlyMapperopt [ BindingTypeIdentifier[?Yield, ?Await] in Type[?Yield, ?Await] MappedAs[?Yield, ?Await]opt ] OptionalMapperopt TypeAnnotation[?Yield, ?Await] ; } ReadonlyMapper : readonly + readonly - readonly OptionalMapper : ? + ? - ? MappedAs[Yield, Await] : as Type[?Yield, ?Await] Note 1

Unlike in most other occurrences, readonly in mapped types allows newlines after it.

Note 2

Parsers may need three-token lookahead to disambiguate MappedType from ObjectType.

Note 3

Actual parsers implement these rules in various ways.

  • Babel allows mixing object literal members and mapped type members.

9.1.11 Template Literal Types

TemplateLiteralType[Yield, Await] : TemplateHead TemplateTypeSpans[?Yield, ?Await] TemplateTypeSpans[Yield, Await] : Type[?Yield, ?Await] TemplateTail Type[?Yield, ?Await] TemplateMiddle TemplateTypeSpans[?Yield, ?Await]

9.1.11.1 Static Semantics: Early Errors

TemplateLiteralType : TemplateHead TemplateTypeSpans TemplateTypeSpans : Type TemplateTail TemplateTypeSpans : Type TemplateMiddle TemplateTypeSpans Note

Actual parsers implement these rules in various ways.

  • TSC permits invalid escapes in template literal types.

9.2 Postfix Types

PostfixType[Yield, Await] : PrimaryType[?Yield, ?Await] ArrayType[?Yield, ?Await] IndexedAccessType[?Yield, ?Await] ArrayType[Yield, Await] : PostfixType[?Yield, ?Await] [ ] IndexedAccessType[Yield, Await] : PostfixType[?Yield, ?Await] [ Type[?Yield, ?Await] ]

9.3 Prefix Types

PrefixType[Yield, Await, Cond] : PostfixType[?Yield, ?Await] KeyofType[?Yield, ?Await, ?Cond] InferType[?Yield, ?Await, ?Cond] ReadonlyType[?Yield, ?Await, ?Cond] KeyofType[Yield, Await, Cond] : keyof PrefixType[?Yield, ?Await, ?Cond] InferType[Yield, Await, Cond] : infer BindingTypeIdentifier[?Yield, ?Await] infer BindingTypeIdentifier[?Yield, ?Await] extends Type[?Yield, ?Await, +Cond] Note 1

unique and asserts are not listed here.

Note 2

Newlines before extends are allowed in InferType, but not in ConditionalType.

Note 3

There is ambiguity in how to interpret extends. Recursive conditional types are banned in the enclosing conditional type's constraint to help resolve this ambiguity.

Examples:

  • 0 extends infer T extends 0 ? 0 : 0 is equivalent to 0 extends (infer T extends 0) ? 0 : 0
  • 0 extends infer T extends 0 ? 0 : 0 ? 0 : 0 looks like 0 extends (infer T extends 0 ? 0 : 0) ? 0 : 0, but it's actually syntax error to resolve ambiguity.
  • 0 extends (infer T extends 0) ? 0 : 0 reads as it is.
  • 0 extends (infer T extends 0 ? 0 : 0) ? 0 : 0 is equivalent to 0 extends ((infer T) extends 0 ? 0 : 0) ? 0 : 0.

However, there is one caveat: some parsers including TSC allow conditional types to appear in return type positions of a function type in a conditional type's constraint part.

For example, 0 extends () => infer T extends 0 ? 0 : 0 ? 0 : 0 is allowed. In this case, it prefers interpretation as conditional types if ? follows the constraint type.

The resulting disambiguation algorithm is as follows:

  • If conditional types are disallowed in the context, interpret extends as part of the InferType.
  • Otherwise, if ? follows the constraint type, interpret extends as part of a conditional type.
  • Otherwise, interpret extends as part of the InferType.

9.3.1 Readonly Types

ReadonlyType[Yield, Await, Cond] : readonly PrefixType[?Yield, ?Await, ?Cond]

9.3.1.1 Static Semantics: Early Errors

ReadonlyType : readonly PrefixType

9.4 Intersection Types

IntersectionType[Yield, Await, Cond] : PrefixType[?Yield, ?Await, ?Cond] & PrefixType[?Yield, ?Await, ?Cond] IntersectionType[?Yield, ?Await, ?Cond] & PrefixType[?Yield, ?Await, ?Cond]

9.5 Union Types

UnionType[Yield, Await, Cond] : IntersectionType[?Yield, ?Await, ?Cond] | IntersectionType[?Yield, ?Await, ?Cond] UnionType[?Yield, ?Await, ?Cond] | IntersectionType[?Yield, ?Await, ?Cond]

9.6 Conditional and Function Types

Type[Yield, Await] : CondLevelType[?Yield, ?Await, +Cond] CondLevelType[Yield, Await, Cond] : UnionType[?Yield, ?Await, ?Cond] FunctionType[?Yield, ?Await, ?Cond] ConstructorType[?Yield, ?Await, ?Cond] [+Cond] ConditionalType[?Yield, ?Await, ?Cond]

9.6.1 Function and Constructor Types

FunctionType[Yield, Await, Cond] : TypeParameters[?Yield, ?Await, +Const, ~InOut]opt ( FormalParameters[?Yield, ?Await] ) => TypeOrTypePredicate[?Yield, ?Await, ?Cond, +Predicate] ConstructorType[Yield, Await, Cond] : abstractopt new TypeParameters[?Yield, ?Await, +Const, ~InOut]opt ( FormalParameters[?Yield, ?Await] ) => TypeOrTypePredicate[?Yield, ?Await, ?Cond, ~Predicate] Note 1

Newlines are allowed between abstract and new.

Note 2

FunctionType and ConstructorType are equivalent to ObjectType with a unique ObjectCallSignature or ObjectConstructSignature, respectively, but note the difference in return type delimiters.

Note 3

Parsers may need unbounded lookahead to disambiguate FunctionType from the type grouping operator ().

Note 4

Actual parsers implement these rules in various ways.

9.6.2 Conditional Types

ConditionalType[Yield, Await, Cond] : UnionType[?Yield, ?Await, ?Cond] [no LineTerminator here] extends CondLevelType[?Yield, ?Await, ~Cond] ? CondLevelType[?Yield, ?Await, +Cond] : CondLevelType[?Yield, ?Await, +Cond]

9.7 Type Predicates

TypeOrTypePredicate[Yield, Await, Cond, Predicate] : [lookahead ≠ IdentifierReference[?Yield, ?Await] [no LineTerminator here] is] CondLevelType[?Yield, ?Await, ?Cond] [+Predicate] TypePredicate[?Yield, ?Await, ?Cond] TypePredicate[Yield, Await, Cond] : IdentifierReference[?Yield, ?Await] [no LineTerminator here] is CondLevelType[?Yield, ?Await, ?Cond] this [no LineTerminator here] is CondLevelType[?Yield, ?Await, ?Cond] asserts [no LineTerminator here] IdentifierReference[?Yield, ?Await] asserts [no LineTerminator here] IdentifierReference[?Yield, ?Await] [no LineTerminator here] is CondLevelType[?Yield, ?Await, ?Cond] asserts [no LineTerminator here] this asserts [no LineTerminator here] this [no LineTerminator here] is CondLevelType[?Yield, ?Await, ?Cond] Note 1

The lookahead rule means that function f(): keyof is {} is understood as a function signature that asserts the type of the variable keyof, rather than a function that returns a key of type is.

Note 2

Parsers may need one-token lookahead to disambiguate asserts from TypeIdentifierReference or TypeNamespaceReference, and this from ThisType.

Note 3

Actual parsers implement these rules in various ways.

  • TSC parses asserts and this is as types of higher precedence, and then reports non-grammatical errors later.
  • TSC parses is type predicates in accessors and constructors as well, and then reports non-grammatical errors later.
  • TSC allows newlines between asserts x / asserts this and is.

9.8 Type Annotations

TypeAnnotation[Yield, Await] : : Type[?Yield, ?Await] VariableTypeAnnotation[Yield, Await] : : Type[?Yield, ?Await] : unique symbol ReturnTypeAnnotation[Yield, Await, Predicate] : : TypeOrTypePredicate[?Yield, ?Await, +Cond, ?Predicate] Note

Actual parsers implement these rules in various ways.

  • TSC parses unique symbol as types of higher precedence, and then reports non-grammatical errors later.

9.8.1 Static Semantics: Early Errors

TypeAnnotation : : Type VariableTypeAnnotation : : Type : unique symbol ReturnTypeAnnotation : : TypeOrTypePredicate

9.9 Type Parameters

TypeParameters[Yield, Await, Const, InOut] : < TypeParameterList[?Yield, ?Await, ?Const, ?InOut] > < TypeParameterList[?Yield, ?Await, ?Const, ?InOut] , > TypeParameterList[Yield, Await, Const, InOut] : TypeParameter[?Yield, ?Await, ?Const, ?InOut] TypeParameterList[?Yield, ?Await, ?Const, ?InOut] , TypeParameter[?Yield, ?Await, ?Const, ?InOut] TypeParameter[Yield, Await, Const, InOut] : RequiredTypeParameter[?Yield, ?Await, ?Const, ?InOut] OptionalTypeParameter[?Yield, ?Await, ?Const, ?InOut] RequiredTypeParameter[Yield, Await, Const, InOut] : BindingTypeIdentifier[?Yield, ?Await] TypeParameterConstraint[?Yield, ?Await]opt [+Const] const [no LineTerminator here] BindingTypeIdentifier[?Yield, ?Await] TypeParameterConstraint[?Yield, ?Await]opt [+InOut] InOutModifier BindingTypeIdentifier[?Yield, ?Await] TypeParameterConstraint[?Yield, ?Await]opt OptionalTypeParameter[Yield, Await, Const, InOut] : BindingTypeIdentifier[?Yield, ?Await] ? TypeParameterConstraint[?Yield, ?Await]opt = Type[?Yield, ?Await] [+Const] const [no LineTerminator here] BindingTypeIdentifier[?Yield, ?Await] ? TypeParameterConstraint[?Yield, ?Await]opt = Type[?Yield, ?Await] [+InOut] InOutModifier BindingTypeIdentifier[?Yield, ?Await] ? TypeParameterConstraint[?Yield, ?Await]opt = Type[?Yield, ?Await] InOutModifier : in [no LineTerminator here] in [no LineTerminator here] out [no LineTerminator here] out [no LineTerminator here] TypeParameterConstraint[Yield, Await] : extends Type[?Yield, ?Await] Note

Type parameter list cannot be empty.

9.9.1 Static Semantics: Early Errors

TypeParameters : < TypeParameterList > < TypeParameterList , > TypeParameterList : TypeParameterList , TypeParameter

9.10 Type Parameters Lookahead Restrictions

TypeParametersLookahead[Yield, Await] : (no production) Note

Not all occurrences of TypeParameters are subject to these lookahead restrictions.

The restriction only apply to generic arrow functions, and additionally to generic async arrow functions in some parser.

9.10.1 Syntax Alterations

By default, TypeParametersLookahead does not match anything.

However, when [[TypeScript]] of the current syntax context is true and [[JSX]] of the current syntax context is true, we add the following productions to TypeParametersLookahead:

TypeParametersLookahead[Yield, Await] : < constopt IdentifierReference[?Yield, ?Await] extends [lookahead ∉ { =, >, / }] < constopt IdentifierReference[?Yield, ?Await] = < constopt IdentifierReference[?Yield, ?Await] , Note 1

You can use trailing comma to disambiguate generic arrow functions of one type parameter from JSX elements, such as <T,>(x: T) => x.

Note 2

Using IdentifierReference instead of BindingIdentifier because BindingIdentifier unconditionally parses yield and await.

Note 3

Actual parsers implement these rules in various ways.

See notes in 13.3.

And when [[TypeScript]] of the current syntax context is true but [[JSX]] of the current syntax context is false, we add the following productions to TypeParametersLookahead:

TypeParametersLookahead[Yield, Await] : <

9.11 Type Arguments

TypeArguments[Yield, Await] : < TypeArgumentList[?Yield, ?Await] > < TypeArgumentList[?Yield, ?Await] , > ExpressionTypeArguments[Yield, Await] : [lookahead = TypeArgumentsLookahead[?Yield, ?Await]] TypeArguments[?Yield, ?Await] TypeArgumentsLookahead[Yield, Await] : (no production) DoesNotFollowTypeArgumentsNLT : this super Literal [ { function class new /= import ( import < import . Identifier but not as PrivateIdentifier yield await ++ -- delete void typeof + - ~ ! < > @ DoesNotFollowTypeArgumentsLT : < > + - TypeArgumentList[Yield, Await] : Type[?Yield, ?Await] TypeArgumentList[?Yield, ?Await] , Type[?Yield, ?Await] Note 1

Type argument list cannot be empty.

Note 2

DoesNotFollowTypeArgumentsNLT is determined based on the following rules:

  • <, >, +, -, and /= do not follow type arguments.
  • (, NoSubstitutionTemplate, and TemplateHead can follow type arguments.
  • Otherwise, binary operators can follow type arguments.
  • Otherwise, tokens that start expressions do not follow type arguments.

9.11.1 Syntax Alterations

By default, TypeArgumentsLookahead does not match anything.

However, when [[TypeScript]] of the current syntax context is true, we add the following production to TypeArgumentsLookahead:

TypeArgumentsLookahead[Yield, Await] : TypeArguments[?Yield, ?Await] [no LineTerminator here] [lookahead ≠ DoesNotFollowTypeArgumentsNLT] TypeArguments[?Yield, ?Await] LineTerminator [lookahead ≠ DoesNotFollowTypeArgumentsLT] Note

Actual parsers implement these rules in various ways.

10 TypeScript Language: Expressions

This section extends ECMAScript Language: Expressions to support TypeScript-specific expressions.

10.1 Primary Expressions

The following grammar extends PrimaryExpression:

PrimaryExpression[Yield, Await] : this IdentifierReference[?Yield, ?Await] Literal ArrayLiteral[?Yield, ?Await] ObjectLiteral[?Yield, ?Await] FunctionExpression ClassExpression[?Yield, ?Await] GeneratorExpression AsyncFunctionExpression AsyncGeneratorExpression RegularExpressionLiteral TemplateLiteral[?Yield, ?Await, ~Tagged] ParenthesizedExpression[?Yield, ?Await] [lookahead = JSXElementLookahead[?Yield, ?Await]] JSXElement[?Yield, ?Await] [lookahead = JSXElementLookahead[?Yield, ?Await]] JSXFragment[?Yield, ?Await] Note 1

PrimaryExpression originally referenced CoverParenthesizedExpressionAndArrowParameterList. See Backtracking over cover grammars for the rationale.

Disambiguation between ArrowHead and parenthesized expressions in PrimaryExpression is still necessary. Most parsers implement it using backtracking, optionally with bounded lookahead for optimization.

Note 2

Actual parsers implement these rules in various ways.

10.1.1 Static Semantics: Early Errors

PrimaryExpression : JSXElement JSXFragment

10.2 Left-Hand-Side Expressions

The following grammar extends MemberExpression:

MemberExpression[Yield, Await] : PrimaryExpression[?Yield, ?Await] MemberExpression[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ] MemberExpression[?Yield, ?Await] . IdentifierName MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] SuperProperty[?Yield, ?Await] MetaProperty new MemberExpression[?Yield, ?Await] Arguments[?Yield, ?Await] MemberExpression[?Yield, ?Await] . PrivateIdentifier MemberExpression[?Yield, ?Await] [no LineTerminator here] ! MemberExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await]

The following grammar extends CallExpression:

CallExpression[Yield, Await] : CoverCallExpressionAndAsyncArrowHead[?Yield, ?Await] SuperCall[?Yield, ?Await] ImportCall[?Yield, ?Await] CallExpression[?Yield, ?Await] Arguments[?Yield, ?Await] CallExpression[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ] CallExpression[?Yield, ?Await] . IdentifierName CallExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] CallExpression[?Yield, ?Await] . PrivateIdentifier CallExpression[?Yield, ?Await] [no LineTerminator here] ! CallExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await]

The following grammar extends OptionalChain:

OptionalChain[Yield, Await] : ?. Arguments[?Yield, ?Await] ?. [ Expression[+In, ?Yield, ?Await] ] ?. IdentifierName ?. TemplateLiteral[?Yield, ?Await, +Tagged] ?. PrivateIdentifier OptionalChain[?Yield, ?Await] Arguments[?Yield, ?Await] OptionalChain[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ] OptionalChain[?Yield, ?Await] . IdentifierName OptionalChain[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] OptionalChain[?Yield, ?Await] . PrivateIdentifier ?. ExpressionTypeArguments[?Yield, ?Await] Arguments[?Yield, ?Await] ?. ExpressionTypeArguments[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] OptionalChain[?Yield, ?Await] [no LineTerminator here] ! OptionalChain[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] Note 1

CallExpression originally referenced CoverCallExpressionAndAsyncArrowHead. See Backtracking over cover grammars for the rationale.

Disambiguation between AsyncArrowHead and CallMemberExpression is still necessary. Most parsers implement it using backtracking, optionally with bounded lookahead for optimization.

Note 2

ExpressionTypeArguments that are not attached to a function call or a new expression are called Instantiation Expressions.

Before TypeScript 4.7, there is no Instantiation Expressions, and the grammer was instead:

MemberExpression[Yield, Await] : MemberExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] new MemberExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] Arguments[?Yield, ?Await] CallExpression[Yield, Await] : MemberExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] Arguments[?Yield, ?Await] CallExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] CallExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] Arguments[?Yield, ?Await] NewExpression[Yield, Await] : new MemberExpression[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] OptionalChain[Yield, Await] : ?. ExpressionTypeArguments[?Yield, ?Await] Arguments[?Yield, ?Await] ?. ExpressionTypeArguments[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] OptionalChain[?Yield, ?Await] ExpressionTypeArguments[?Yield, ?Await] Arguments[?Yield, ?Await]

Most TypeScript parsers represent these constructions differently from Instantiation Expressions.

10.2.1 Static Semantics: Early Errors

OptionalChain : ?. ExpressionTypeArguments TemplateLiteral
  • It is a Syntax Error if any source text is matched by this production.
MemberExpression : MemberExpression ! MemberExpression ExpressionTypeArguments CallExpression : CallExpression ! CallExpression ExpressionTypeArguments OptionalChain : ?. ExpressionTypeArguments Arguments ?. ExpressionTypeArguments TemplateLiteral OptionalChain ! OptionalChain ExpressionTypeArguments

10.2.2 Runtime Semantics: Evaluation

MemberExpression : MemberExpression !
  1. Return ? Evaluation of MemberExpression. This may be of type Reference.
MemberExpression : MemberExpression ExpressionTypeArguments
  1. Return ? Evaluation of MemberExpression. This may be of type Reference.
CallExpression : CallExpression !
  1. Return ? Evaluation of CallExpression. This may be of type Reference.
CallExpression : CallExpression ExpressionTypeArguments
  1. Return ? Evaluation of CallExpression. This may be of type Reference.

10.2.3 Runtime Semantics: ChainEvaluation

The syntax-directed operation ChainEvaluation takes arguments baseValue (an ECMAScript language value) and baseReference (an ECMAScript language value or a Reference Record) and returns either a normal completion containing either an ECMAScript language value or a Reference Record, or an abrupt completion. It is defined piecewise over the following productions:

OptionalChain : ?. ExpressionTypeArguments Arguments
  1. Let thisChain be this OptionalChain.
  2. Let tailCall be IsInTailPosition(thisChain).
  3. Return ? EvaluateCall(baseValue, baseReference, Arguments, tailCall).
OptionalChain : OptionalChain !
  1. Return ? ChainEvaluation of OptionalChain with arguments baseValue and baseReference. This may be of type Reference.
OptionalChain : OptionalChain ExpressionTypeArguments
  1. Return ? ChainEvaluation of OptionalChain with arguments baseValue and baseReference. This may be of type Reference.

10.3 Unary Operators

The following grammar extends UnaryExpression:

UnaryExpression[Yield, Await] : UpdateExpression[?Yield, ?Await] delete UnaryExpression[?Yield, ?Await] void UnaryExpression[?Yield, ?Await] typeof UnaryExpression[?Yield, ?Await] + UnaryExpression[?Yield, ?Await] - UnaryExpression[?Yield, ?Await] ~ UnaryExpression[?Yield, ?Await] ! UnaryExpression[?Yield, ?Await] [+Await] AwaitExpression[?Yield] Note
The productions above is the same as the original ECMA-262 grammar, but see the next clause.

10.3.1 Syntax Alterations

When [[TypeScript]] of the current syntax context is true and [[JSX]] of the current syntax context is false, we add the following production to the grammar of UnaryExpression:

UnaryExpression[Yield, Await] : < Type[?Yield, ?Await] > UnaryExpression[?Yield, ?Await] Note

Only one of JSX tags and legacy type assertions can be enabled at a time. When neither of [[TypeScript]] nor [[JSX]] is enabled, the choice is arbitrary as we would rule it out with Early Errors anyway. We choose to enable JSX tags in this case to imitate TSC's behaviour.

10.3.2 Runtime Semantics: Evaluation

UnaryExpression : < Type > UnaryExpression
  1. Return ? Evaluation of UnaryExpression. This may be of type Reference.

10.4 Relational Operators

The following grammar extends RelationalExpression:

RelationalExpression[In, Yield, Await] : ShiftExpression[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] [lookahead ≠ TypeArgumentsLookahead[?Yield, ?Await]] < ShiftExpression[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] > ShiftExpression[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] <= ShiftExpression[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] >= ShiftExpression[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] instanceof ShiftExpression[?Yield, ?Await] [+In] RelationalExpression[+In, ?Yield, ?Await] in ShiftExpression[?Yield, ?Await] [+In] PrivateIdentifier in ShiftExpression[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] [no LineTerminator here] as Type[?Yield, ?Await] RelationalExpression[?In, ?Yield, ?Await] [no LineTerminator here] satisfies Type[?Yield, ?Await] Note

The production for < is modified from the original ECMA-262 grammar to include a lookahead restriction that prevents ambiguity with ExpressionTypeArguments.

Its semantics is the same, as the derivation tree is unchanged.

This modification takes effect only when [[TypeScript]] is true. See Type Arguments Syntax Alterations.

10.4.1 Runtime Semantics: Evaluation

RelationalExpression : RelationalExpression as Type
  1. Return ? Evaluation of RelationalExpression. This may be of type Reference.
RelationalExpression : RelationalExpression satisfies Type
  1. Return ? Evaluation of RelationalExpression. This may be of type Reference.

11 TypeScript Language: Statements and Declarations

This section extends ECMAScript Language: Statements and Declarations to support TypeScript-specific syntax.

The following grammar extends Declaration:

Declaration[Yield, Await] : HoistableDeclaration[?Yield, ?Await, ~Default] ClassDeclaration[?Yield, ?Await, ~Default] LexicalDeclaration[+In, ?Yield, ?Await] TopLevelAmbientDeclaration[?Yield, ?Await] FunctionOverloadDeclaration[?Yield, ?Await, ~Default] TypeAliasDeclaration[?Yield, ?Await] InterfaceDeclaration[?Yield, ?Await]

11.1 Statement Semantics

11.1.1 Static Semantics: Early Errors

Declaration : TopLevelAmbientDeclaration FunctionOverloadDeclaration TypeAliasDeclaration InterfaceDeclaration

11.1.2 Runtime Semantics: Evaluation

Declaration : TopLevelAmbientDeclaration FunctionOverloadDeclaration TypeAliasDeclaration InterfaceDeclaration
  1. Return empty.

11.2 Declarations and the Variable Statement

The following grammar extends LexicalBinding:

LexicalBinding[In, Yield, Await] : BindingIdentifier[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt Initializer[?In, ?Yield, ?Await]opt BindingPattern[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt Initializer[?In, ?Yield, ?Await] [+In] BindingIdentifier[?Yield, ?Await] [no LineTerminator here] ! TypeAnnotation[?Yield, ?Await]

The following grammar extends VariableDeclaration:

VariableDeclaration[In, Yield, Await] : BindingIdentifier[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt Initializer[?In, ?Yield, ?Await]opt BindingPattern[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt Initializer[?In, ?Yield, ?Await] [+In] BindingIdentifier[?Yield, ?Await] [no LineTerminator here] ! TypeAnnotation[?Yield, ?Await] Note 1

The [+In] condition is used here to forbid the use of the definite assignment assertion (!) in for statements.

Note 2

Actual parsers implement these rules in various ways.

  • Babel and SWC allow definite assignment assertions (!) to be used together with initializers.
  • Babel and SWC allow definite assignment assertions (!) to be used without type annotations.
  • Babel and SWC allow definite assignment assertions (!) to be used in for statements as well.

11.2.1 Syntax Mapping

The following productions:

LexicalBinding : BindingIdentifier TypeAnnotationopt Initializeropt BindingPattern TypeAnnotationopt Initializer

are mapped to the following productions, respectively:

LexicalBinding : BindingIdentifier Initializeropt BindingPattern Initializer

The following production:

LexicalBinding : BindingIdentifier [no LineTerminator here] ! TypeAnnotation

is mapped to the following production:

LexicalBinding : BindingIdentifier Initializeropt Note 1

Transformation is uniquely determined because Initializer is optional in the original production.

The following productions:

VariableDeclaration : BindingIdentifier TypeAnnotationopt Initializeropt BindingPattern TypeAnnotationopt Initializer

are mapped to the following productions, respectively:

VariableDeclaration : BindingIdentifier Initializeropt BindingPattern Initializer

The following production:

VariableDeclaration : BindingIdentifier [no LineTerminator here] ! TypeAnnotation

is mapped to the following production:

VariableDeclaration : BindingIdentifier Initializeropt Note 2

Transformation is uniquely determined because Initializer is optional in the original production.

11.2.2 Static Semantics: Early Errors

LexicalBinding : BindingIdentifier ! TypeAnnotation VariableDeclaration : BindingIdentifier ! TypeAnnotation Note

The Early Error rules for TypeAnnotation should have ruled out this production. An additional check is here for completeness, as some parsers allow ! without TypeAnnotation.

11.3 Iteration Statements

11.3.1 The for Statement

Note

This specification does not update ForStatement here. Instead, for statements are updated through LexicalDeclaration and VariableStatement in Declarations and the Variable Statement.

11.3.2 The for-in, for-of, and for-await-of Statements

Note 1

This specification does not currently update ForInOfStatement here.

Note 2

Actual parsers implement these rules in various ways.

  • Babel and SWC allow use of definite assignment assertions ! in the variable declarations of for-in, for-of, and for-await-of statements.
  • Babel allows use of type annotations in the variable declarations of for-in, for-of, and for-await-of statements as well.

11.4 The try Statement

The following grammar extends CatchParameter:

CatchParameter[Yield, Await] : BindingIdentifier[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt BindingPattern[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt Note 1

Note 2

The index type in CatchParameter must resolve to unknown or any, but it's beyond parsers' capabilities to enforce this.

It also means that it is meaningless to have TypeAnnotation after BindingPattern in this context, but we do not rule out this syntax for the same reason.

11.4.1 Syntax Mapping

The following productions:

CatchParameter : BindingIdentifier TypeAnnotationopt BindingPattern TypeAnnotationopt

are mapped to the following productions, respectively:

CatchParameter : BindingIdentifier BindingPattern

11.5 Ambient and Overload Declarations

TopLevelAmbientDeclaration[Yield, Await] : declare [no LineTerminator here] AmbientDeclaration[?Yield, ?Await] AmbientDeclaration[Yield, Await] : AmbientVariableDeclaration[?Yield, ?Await] AmbientFunctionDeclaration[?Yield, ?Await, ~Default] AmbientClassDeclaration[?Yield, ?Await]

11.5.1 Ambient Variable Declarations

AmbientVariableDeclaration[Yield, Await] : var AmbientBindingList[~Init, ?Yield, ?Await] ; let AmbientBindingList[~Init, ?Yield, ?Await] ; const AmbientBindingList[+Init, ?Yield, ?Await] ; AmbientBindingList[Init, Yield, Await] : AmbientVariableBinding[?Init, ?Yield, ?Await] AmbientBindingList[?Init, ?Yield, ?Await] , AmbientVariableBinding[?Init, ?Yield, ?Await] AmbientVariableBinding[Init, Yield, Await] : BindingIdentifier[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt BindingPattern[?Yield, ?Await] TypeAnnotation[?Yield, ?Await]opt [+Init] BindingIdentifier[?Yield, ?Await] = AmbientInitLiteral[?Yield, ?Await] [+Init] BindingPattern[?Yield, ?Await] = AmbientInitLiteral[?Yield, ?Await] AmbientInitLiteral[Yield, Await] : BooleanLiteral StringLiteral NoSubstitutionTemplate NumericLiteral - NumericLiteral EnumReferenceExpression[?Yield, ?Await] EnumReferenceExpression[Yield, Await] : EntityNameExpression[?Yield, ?Await] . IdentifierName EntityNameExpression[?Yield, ?Await] [ EnumReferenceKeyExpression ] EnumReferenceKeyExpression : StringLiteral NoSubstitutionTemplate NumericLiteral - NumericLiteral EntityNameExpression[Yield, Await] : IdentifierReference[?Yield, ?Await] EntityNameExpression[?Yield, ?Await] . IdentifierName Note 1

Initializers are only allowed here only when it is a declare const initialized with literal-like values without type annotations.

Note 2

null cannot be used as an initializer in declare const.

Note 3

Interestingly, initializers can be currently used in conjunction with binding patterns, enabling use of declare const { length } = "foo";.

Note 4

EnumReferenceExpression must resolve to a constant enum member, but it's beyond parsers' capabilities to enforce this.

Note 5

Actual parsers implement these rules in various ways.

11.5.1.1 Static Semantics: Early Errors

EnumReferenceKeyExpression : NumericLiteral - NumericLiteral

11.5.2 Ambient Function Declarations and Overloads

AmbientFunctionDeclaration[Yield, Await, Default] : function BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) TypeAnnotation[?Yield, ?Await]opt ; [+Default] function TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) TypeAnnotation[?Yield, ?Await]opt ; FunctionOverloadDeclaration[Yield, Await, Default] : function BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) TypeAnnotation[?Yield, ?Await]opt ; async [no LineTerminator here] function BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, +Await] ) TypeAnnotation[?Yield, ?Await]opt ; function * BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, ~Await] ) TypeAnnotation[?Yield, ?Await]opt ; async [no LineTerminator here] function BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, +Await] ) TypeAnnotation[?Yield, ?Await]opt ; [+Default] function TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) TypeAnnotation[?Yield, ?Await]opt ; [+Default] async [no LineTerminator here] function TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, +Await] ) TypeAnnotation[?Yield, ?Await]opt ; [+Default] function * TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, ~Await] ) TypeAnnotation[?Yield, ?Await]opt ; [+Default] async [no LineTerminator here] function * TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, +Await] ) TypeAnnotation[?Yield, ?Await]opt ; Note 1

There is no async and/or generator ambient function declarations. async and * are stripped when generating declaration files.

Note 2

FunctionOverloadDeclaration must be placed before a HoistableDeclaration or another FunctionOverloadDeclaration of the same name.

This restriction is fairly marginal; it can be thought of as syntax error or type error. Here we classify it as a type error.

11.5.2.1 Static Semantics: Early Errors

AmbientFunctionDeclaration : function BindingIdentifier TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; function TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; FunctionOverloadDeclaration : function BindingIdentifier TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; async function BindingIdentifier TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; function * BindingIdentifier TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; async function * BindingIdentifier TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; function TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; async function TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; function * TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; async function * TypeParametersopt ( FormalParameters ) TypeAnnotationopt ; Note

Actual parsers implement these rules in various ways.

  • Babel and SWC allow default values for parameters in ambient function declarations and overloads.
  • Babel and SWC allow default values for binding patterns in parameters in ambient function declarations and overloads.

12 TypeScript Language: Functions and Classes

This section extends ECMAScript Language: Functions and Classes to support TypeScript-specific syntax.

12.1 Parameter Lists

The following grammar extends FormalParameters:

FormalParameters[Yield, Await] : [empty] FunctionRestParameter[?Yield, ?Await] FormalParameterList[?Yield, ?Await] FormalParameterList[?Yield, ?Await] , FormalParameterList[?Yield, ?Await] , FunctionRestParameter[?Yield, ?Await] FunctionThisParameter[?Yield, ?Await] FunctionThisParameter[?Yield, ?Await] , FunctionThisParameter[?Yield, ?Await] , FunctionRestParameter[?Yield, ?Await] FunctionThisParameter[?Yield, ?Await] , FormalParameterList[?Yield, ?Await] FunctionThisParameter[?Yield, ?Await] , FormalParameterList[?Yield, ?Await] , FunctionThisParameter[?Yield, ?Await] , FormalParameterList[?Yield, ?Await] , FunctionRestParameter[?Yield, ?Await] FunctionThisParameter[Yield, Await] : this TypeAnnotation[?Yield, ?Await]opt

The following grammar extends FunctionRestParameter:

FunctionRestParameter[Yield, Await] : BindingRestElement[?Yield, ?Await] ?opt TypeAnnotation[?Yield, ?Await]opt

The following grammar extends FormalParameter:

FormalParameter[Yield, Await] : BindingIdentifier[?Yield, ?Await] ?opt TypeAnnotation[?Yield, ?Await]opt Initializer[+In, ?Yield, ?Await]opt BindingPattern[?Yield, ?Await] ?opt TypeAnnotation[?Yield, ?Await]opt Initializer[+In, ?Yield, ?Await]opt

12.1.1 Syntax Mapping

The following production:

FormalParameters : FunctionThisParameter[?Yield, ?Await]

is mapped to the following production:

FormalParameters : [empty]

The following productions:

FormalParameters : FunctionThisParameter , FunctionThisParameter , FunctionRestParameter FunctionThisParameter , FormalParameterList FunctionThisParameter , FormalParameterList , FunctionThisParameter , FormalParameterList , FunctionRestParameter

are mapped to the following productions, respectively:

FormalParameters : [empty] FunctionRestParameter FormalParameterList FormalParameterList , FormalParameterList , FunctionRestParameter

12.1.2 Static Semantics: Early Errors

FormalParameters : FunctionThisParameter FunctionThisParameter , FunctionThisParameter , FunctionRestParameter FunctionThisParameter , FormalParameterList FunctionThisParameter , FormalParameterList , FunctionThisParameter , FormalParameterList , FunctionRestParameter Note

function f(this) {} is allowed in TypeScript, but not in JavaScript, despite this without type annotation is useless.

12.1.3 Static Semantics: ContainsThisParameter

The syntax-directed operation ContainsThisParameter takes no arguments and returns a Boolean. It determines whether the syntax it is applied to contains a this parameter. It is defined piecewise over the following productions:

FormalParameters : [empty] FunctionRestParameter FormalParameterList FormalParameterList , FormalParameterList , FunctionRestParameter
  1. Return false.
FormalParameters : FunctionThisParameter FunctionThisParameter , FunctionThisParameter , FunctionRestParameter FunctionThisParameter , FormalParameterList FunctionThisParameter , FormalParameterList , FunctionThisParameter , FormalParameterList , FunctionRestParameter
  1. Return true.

12.2 Function Definitions

The following grammar extends FunctionDeclaration:

FunctionDeclaration[Yield, Await, Default] : function BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { FunctionBody[~Yield, ~Await] } [+Default] function TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { FunctionBody[~Yield, ~Await] }

The following grammar extends FunctionExpression:

FunctionExpression : function BindingIdentifier[~Yield, ~Await]opt TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, ~Await] ) ReturnTypeAnnotation[~Yield, ~Await, +Predicate]opt { FunctionBody[~Yield, ~Await] }

12.2.1 Syntax Mapping

The following productions:

FunctionDeclaration : function BindingIdentifier TypeParameters[?Yield, ?Await]opt ( FormalParameters ) ReturnTypeAnnotationopt { FunctionBody } function TypeParameters[?Yield, ?Await]opt ( FormalParameters ) ReturnTypeAnnotationopt { FunctionBody }

are mapped to the following productions, respectively:

FunctionDeclaration : function BindingIdentifier ( FormalParameters ) { FunctionBody } function ( FormalParameters ) { FunctionBody }

The following production:

FunctionExpression : function BindingIdentifieropt TypeParameters[?Yield, ?Await]opt ( FormalParameters ) ReturnTypeAnnotationopt { FunctionBody }

is mapped to the following production:

FunctionExpression : function BindingIdentifieropt ( FormalParameters ) { FunctionBody }

12.3 Arrow Function Definitions

The following grammar extends ArrowParameters:

ArrowFunction[In, Yield, Await] : ArrowBindingIdentifier[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In] ArrowHead[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In] ArrowBindingIdentifier[Yield, Await] : BindingIdentifier[?Yield, ?Await] ArrowHead[Yield, Await] : ArrowFormalParameters[?Yield, ?Await] ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt [lookahead = TypeParametersLookahead[?Yield, ?Await]] TypeParameters[?Yield, ?Await] ArrowFormalParameters[?Yield, ?Await] ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt Note

ArrowHead originally referenced CoverParenthesizedExpressionAndArrowParameterList. See Backtracking over cover grammars for the rationale.

Disambiguation between ArrowHead and parenthesized expressions in PrimaryExpression is still necessary. Most parsers implement it using backtracking, optionally with bounded lookahead for optimization.

12.3.1 Static Semantics: Early Errors

ArrowFunction : ArrowHead [no LineTerminator here] => ConciseBody

12.4 Method Definitions

The following grammar extends MethodDefinition:

MethodDefinition[Yield, Await] : ClassElementName[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( UniqueFormalParameters[~Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { FunctionBody[~Yield, ~Await] } GeneratorMethod[?Yield, ?Await] AsyncMethod[?Yield, ?Await] AsyncGeneratorMethod[?Yield, ?Await] get ClassElementName[?Yield, ?Await] ( ) ReturnTypeAnnotation[?Yield, ?Await, ~Predicate]opt { FunctionBody[~Yield, ~Await] } set ClassElementName[?Yield, ?Await] ( PropertySetParameterList ) { FunctionBody[~Yield, ~Await] } Note

Actual parsers implement these rules in various ways.

  • Babel allows type parameters in get and set accessors.
  • Babel and SWC allow return type annotations in set accessors.
  • Babel and SWC allow type predicates in get accessors.
  • Babel and SWC allow this parameters in get and set accessors.

This note also applies to GeneratorMethod, AsyncMethod, and AsyncGeneratorMethod.

12.4.1 Syntax Mapping

The following production:

MethodDefinition : ClassElementName TypeParametersopt ( UniqueFormalParameters ) ReturnTypeAnnotationopt { FunctionBody }

is mapped to the following production:

MethodDefinition : ClassElementName ( UniqueFormalParameters ) { FunctionBody }

The following production:

MethodDefinition : get ClassElementName ( ) ReturnTypeAnnotationopt { FunctionBody }

is mapped to the following production:

MethodDefinition : get ClassElementName ( ) { FunctionBody }

12.4.2 Static Semantics: Early Errors

MethodDefinition : ClassElementName TypeParametersopt ( UniqueFormalParameters ) ReturnTypeAnnotationopt { FunctionBody } Note

Actual parsers implement these rules in various ways.

12.5 Generator Function Definitions

The following grammar extends GeneratorDeclaration:

GeneratorDeclaration[Yield, Await, Default] : function * BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { GeneratorBody } [+Default] function * TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { GeneratorBody }

The following grammar extends GeneratorExpression:

GeneratorExpression : function * BindingIdentifier[+Yield, ~Await]opt TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { GeneratorBody }

The following grammar extends GeneratorMethod:

GeneratorMethod[Yield, Await] : * ClassElementName[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( UniqueFormalParameters[+Yield, ~Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { GeneratorBody } Note

Generators cannot have meaningful type predicates because their return types cannot be void or boolean. We allow them here nonetheless because the errors are more like type errors than syntax errors.

12.5.1 Syntax Mapping

The following productions:

GeneratorDeclaration : function * BindingIdentifier TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { GeneratorBody } function * TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { GeneratorBody }

are mapped to the following productions, respectively:

GeneratorDeclaration : function * BindingIdentifier ( FormalParameters ) { GeneratorBody } function * ( FormalParameters ) { GeneratorBody }

The following production:

GeneratorExpression : function * BindingIdentifieropt TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { GeneratorBody }

is mapped to the following production:

GeneratorExpression : function * BindingIdentifieropt ( FormalParameters ) { GeneratorBody }

The following production:

GeneratorMethod : * ClassElementName TypeParametersopt ( UniqueFormalParameters ) ReturnTypeAnnotationopt { GeneratorBody }

is mapped to the following production:

GeneratorMethod : * ClassElementName ( UniqueFormalParameters ) { GeneratorBody }

12.6 Async Generator Function Definitions

Syntax

AsyncGeneratorDeclaration[Yield, Await, Default] : async [no LineTerminator here] function * BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncGeneratorBody } [+Default] async [no LineTerminator here] function * TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncGeneratorBody } AsyncGeneratorExpression : async [no LineTerminator here] function * BindingIdentifier[+Yield, +Await]opt TypeParameters[?Yield, ?Await]opt ( FormalParameters[+Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncGeneratorBody } AsyncGeneratorMethod[Yield, Await] : async [no LineTerminator here] * ClassElementName[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( UniqueFormalParameters[+Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncGeneratorBody } Note

Async generators cannot have meaningful type predicates because their return types cannot be void or boolean. We allow them here nonetheless because the errors are more like type errors than syntax errors.

12.6.1 Syntax Mapping

The following productions:

AsyncGeneratorDeclaration : async [no LineTerminator here] function * BindingIdentifier TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { AsyncGeneratorBody } async [no LineTerminator here] function * TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { AsyncGeneratorBody }

are mapped to the following productions, respectively:

AsyncGeneratorDeclaration : async [no LineTerminator here] function * BindingIdentifier ( FormalParameters ) { AsyncGeneratorBody } async [no LineTerminator here] function * ( FormalParameters ) { AsyncGeneratorBody }

The following production:

AsyncGeneratorExpression : async [no LineTerminator here] function * BindingIdentifieropt TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { AsyncGeneratorBody }

is mapped to the following production:

AsyncGeneratorExpression : async [no LineTerminator here] function * BindingIdentifieropt ( FormalParameters ) { AsyncGeneratorBody }

The following production:

AsyncGeneratorMethod : async [no LineTerminator here] * ClassElementName TypeParametersopt ( UniqueFormalParameters ) ReturnTypeAnnotationopt { AsyncGeneratorBody }

is mapped to the following production:

AsyncGeneratorMethod : async [no LineTerminator here] * ClassElementName ( UniqueFormalParameters ) { AsyncGeneratorBody }

12.7 Async Function Definitions

AsyncFunctionDeclaration[Yield, Await, Default] : async [no LineTerminator here] function BindingIdentifier[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncFunctionBody } [+Default] async [no LineTerminator here] function TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncFunctionBody } AsyncFunctionExpression : async [no LineTerminator here] function BindingIdentifier[~Yield, +Await]opt TypeParameters[?Yield, ?Await]opt ( FormalParameters[~Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncFunctionBody } AsyncMethod[Yield, Await] : async [no LineTerminator here] ClassElementName[?Yield, ?Await] TypeParameters[?Yield, ?Await]opt ( UniqueFormalParameters[~Yield, +Await] ) ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt { AsyncFunctionBody } Note

Async functions cannot have meaningful type predicates because their return types cannot be void or boolean. We allow them here nonetheless because the errors are more like type errors than syntax errors.

12.7.1 Syntax Mapping

The following productions:

AsyncFunctionDeclaration : async [no LineTerminator here] function BindingIdentifier TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { AsyncFunctionBody } async [no LineTerminator here] function TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { AsyncFunctionBody }

are mapped to the following productions, respectively:

AsyncFunctionDeclaration : async [no LineTerminator here] function BindingIdentifier ( FormalParameters ) { AsyncFunctionBody } async [no LineTerminator here] function ( FormalParameters ) { AsyncFunctionBody }

The following production:

AsyncFunctionExpression : async [no LineTerminator here] function BindingIdentifieropt TypeParametersopt ( FormalParameters ) ReturnTypeAnnotationopt { AsyncFunctionBody }

is mapped to the following production:

AsyncFunctionExpression : async [no LineTerminator here] function BindingIdentifieropt ( FormalParameters ) { AsyncFunctionBody }

The following production:

AsyncMethod : async [no LineTerminator here] ClassElementName TypeParametersopt ( UniqueFormalParameters ) ReturnTypeAnnotationopt { AsyncFunctionBody }

is mapped to the following production:

AsyncMethod : async [no LineTerminator here] ClassElementName ( UniqueFormalParameters ) { AsyncFunctionBody }

12.8 Async Arrow Function Definitions

The following grammar extends AsyncArrowFunction:

AsyncArrowFunction[In, Yield, Await] : async [no LineTerminator here] AsyncArrowBindingIdentifier[?Yield] [no LineTerminator here] => AsyncConciseBody[?In] AsyncArrowHead[?Yield] [no LineTerminator here] => AsyncConciseBody[?In]

The following grammar extends AsyncArrowHead:

AsyncArrowHead[Yield] : async [no LineTerminator here] TypeParameters[?Yield, ?Await]opt ArrowFormalParameters[?Yield, +Await] ReturnTypeAnnotation[?Yield, ?Await, +Predicate]opt Note 1

AsyncArrowFunction originally referenced CoverCallExpressionAndAsyncArrowHead. See Backtracking over cover grammars for the rationale.

Disambiguation between AsyncArrowHead and CallMemberExpression is still necessary. Most parsers implement it using backtracking, optionally with bounded lookahead for optimization.

Note 2

This specification slightly alters the use of ArrowFormalParameters, namely by switching from [~Yield] to [?Yield].

This is to accommodate the removal of cover grammars; the use of an identifier named yield in an async arrow function parameter list in a non-strict generator context should have been ruled out when first parsed as MemberExpression. This specification uses [?Yield] to correctly reflect this behavior.

This means yield is recognized as a yield expression instead, but the expression would instead be forbidden by the Early Error rule for FormalParameters.

Note 3

Async arrow functions cannot have meaningful type predicates because their return types cannot be void or boolean. We allow them here nonetheless because the errors are more like type errors than syntax errors.

Note 4

Actual parsers implement these rules in various ways.

  • When JSX is enabled, TSC and SWC impose the same lookahead restriction as ArrowFunction.

13 JSX Expressions

13.1 JSX Identifiers

JSXSimpleIdentifier : JSXIdentifierName but only if IsJSXLiteralName of JSXIdentifierName is false JSXLiteralIdentifier : JSXIdentifierName but only if IsJSXLiteralName of JSXIdentifierName is true and StringValue of JSXIdentifierName is not this JSXThis : JSXIdentifierName but only if StringValue of JSXIdentifierName is this JSXIdentifierReference[Yield, Await] : JSXIdentifierName Note 1

JSXSimpleIdentifier, JSXLiteralIdentifier, and JSXThis are mutually exclusive and exhaustive classifications of JSXIdentifierName.

Note 2

JSXThis is matched based on its StringValue, not its verbatim spelling, to reflect the nuances of actual implementations. For example, SWC interprets the element name of <\u{74}his /> as equivalent to ThisExpression.

For implementations that disallow escaped identifiers in JSX elements, JSXThis is always verbatimly this.

13.1.1 Static Semantics: Early Errors

JSXIdentifierReference : JSXIdentifierName Note 1

All reserved words mentioned here start with a lowercase letter. Thus we can assume JSXSimpleIdentifier satisfies the same restrictions.

Note 2

Actual parsers implement these rules in various ways.

In fact, these rules are artificial conditions to ensure sanity of the generated code, and many parsers just emit broken code.

13.2 JSX Elements and Fragments

JSXElement[Yield, Await] : JSXSelfClosingElement[?Yield, ?Await] JSXOpeningElement[?Yield, ?Await] JSXChildren[?Yield, ?Await]opt JSXClosingElement[?Yield, ?Await] JSXFragment[Yield, Await] : < > JSXChildren[?Yield, ?Await]opt < / > JSXSelfClosingElement[Yield, Await] : < JSXElementName[?Yield, ?Await] TypeArguments[?Yield, ?Await]opt JSXAttributes[?Yield, ?Await]opt / > JSXOpeningElement[Yield, Await] : < JSXElementName[?Yield, ?Await] TypeArguments[?Yield, ?Await]opt JSXAttributes[?Yield, ?Await]opt > JSXClosingElement[Yield, Await] : < / JSXElementName[?Yield, ?Await] > Note 1

Whitespace is allowed within JSX elements where it is disallowed in HTML.

For example, the following are all valid JSX elements:

  • < div ></ div >
  • < div >< / div >, though TSC and SWC disallow it
  • < /**/div/**/title/**/=/**/"value"/**/></ /**/div/**/>
  • < img / >
  • <svg : path></svg : path>
Note 2

Actual parsers implement these rules in various ways.

  • TSC and SWC disallow whitespace between < and /.
  • TSC and SWC tokenizes </ as a single token, thus allowing:
    <div><///
    div>;
  • TSC and SWC tokenizes </ as a single token where it is expected, thus disallowing <div></**/img/></div>. However, they still accept </**/img/> as a PrimaryExpression.

13.2.1 Static Semantics: Early Errors

JSXElement : JSXOpeningElement JSXChildrenopt JSXClosingElement

13.2.2 Runtime Semantics: Evaluation

PrimaryExpression : JSXElement JSXFragment
  1. Let ctx be the current syntax context.
  2. Let jsx be ? JSXPreEvaluation(PrimaryExpression).
  3. Return ? EvaluateJSXElement(ctx, jsx).

13.3 JSX Lookahead Restrictions

JSXElementLookahead[Yield, Await] : < Note

See TypeParametersLookahead for the inverse.

13.3.1 Syntax Alterations

When [[TypeScript]] of the current syntax context is true and [[JSX]] of the current syntax context is true, we replace the production of JSXElementLookahead:

JSXElementLookahead[Yield, Await] : <

with:

JSXElementLookahead[Yield, Await] : < [lookahead ∉ { const, Identifier }] < IdentifierReference[?Yield, ?Await] [lookahead ≠ extends] < IdentifierReference[?Yield, ?Await] extends = < IdentifierReference[?Yield, ?Await] extends > < IdentifierReference[?Yield, ?Await] extends / > [+Yield] < yield [+Await] < await < const [lookahead ≠ Identifier] < const IdentifierReference[?Yield, ?Await] [lookahead ∉ { extends, = }] < const IdentifierReference[?Yield, ?Await] extends = < const IdentifierReference[?Yield, ?Await] extends > < const IdentifierReference[?Yield, ?Await] extends / > [+Yield] < const yield [+Await] < const await Note 1

Based on the rules above, you would better avoid naming an attribute extends or naming an intrinsic element const.

Note 2

Actual parsers implement these rules in various ways.

The lookahead above is based on the negation of TSC's lookahead rule for generic arrow functions.

However, there is a fundamental disagreement among parsers how to disambiguate <: a bounded or unbounded lookahead.

This spec is based on bounded lookahead, which is more conservative.

When [[TypeScript]] of the current syntax context is true and [[JSX]] of the current syntax context is false, we remove the production of JSXElementLookahead:

JSXElementLookahead[Yield, Await] : <

leaving no productions for JSXElementLookahead.

Note 3

Therefore, for TypeScript source without JSX, < at the start of an expression is always interpreted as the less-than operator.

13.4 JSX Element Names

JSXElementName[Yield, Await] : JSXSimpleIdentifier JSXLiteralIdentifier JSXThis JSXNamespacedName JSXMemberExpression[?Yield, ?Await] JSXNamespacedName : JSXIdentifierName : JSXIdentifierName JSXMemberExpression[Yield, Await] : JSXIdentifierReference[?Yield, ?Await] . JSXIdentifierName JSXMemberExpression[?Yield, ?Await] . JSXIdentifierName Note

JSXIdentifierName does not exclude reserved words. Therefore, <var/> is a valid JSX element.

13.4.1 Static Semantics: Early Errors

JSXMemberExpression : JSXIdentifierReference . JSXIdentifierName JSXMemberExpression . JSXIdentifierName Note

Actual parsers implement these rules in various ways.

  • SWC allows hyphens the property name here, and emits the broken code.

13.4.2 Static Semantics: StringValue

JSXNamespacedName : JSXIdentifierName : JSXIdentifierName
  1. Let namespace be the StringValue of the first JSXIdentifierName.
  2. Let name be the StringValue of the second JSXIdentifierName.
  3. Return the concatenation of namespace, U+003A (COLON), and name.
JSXIdentifierName :: JSXIdentifierStart JSXIdentifierName JSXIdentifierPart
  1. Let idTextUnescaped be the IdentifierCodePoints of JSXIdentifierName.
  2. Return CodePointsToString(idTextUnescaped).
JSXMemberExpression : JSXMemberExpressionBase . JSXIdentifierName
  1. Let object be the StringValue of JSXMemberExpressionBase.
  2. Let property be the StringValue of JSXIdentifierName.
  3. Return the concatenation of object, U+002E (FULL STOP), and property.
JSXMemberExpressionBase : JSXMemberExpression . JSXIdentifierName
  1. Let object be the StringValue of JSXMemberExpression.
  2. Let property be the StringValue of JSXIdentifierName.
  3. Return the concatenation of object, U+002E (FULL STOP), and property.

13.4.3 Runtime Semantics: Evaluation

Note

We resolve all expressions to values rather than references here and now, as all known transforms use them as values.

JSXElementName : JSXSimpleIdentifier
  1. Let ref be ? ResolveBinding(StringValue of JSXSimpleIdentifier).
  2. Return ? GetValue(ref).
JSXElementName : JSXThis
  1. Return ? ResolveThisBinding().
JSXMemberExpression : JSXIdentifierReference . JSXIdentifierName
  1. Let baseRef be ? ResolveBinding(StringValue of JSXIdentifierReference).
  2. Let baseValue be ? GetValue(baseRef).
  3. Let property be the StringValue of JSXIdentifierName.
  4. Return ? GetV(baseValue, property).
JSXMemberExpression : JSXMemberExpression . JSXIdentifierName
  1. Let base be ? Evaluation of the derived JSXMemberExpression.
  2. Let property be the StringValue of JSXIdentifierName.
  3. Return ? GetV(base, property).

13.5 JSX Attributes

JSXAttributes[Yield, Await] : JSXAttributeListElement[?Yield, ?Await] JSXAttributes[?Yield, ?Await] JSXAttributeListElement[?Yield, ?Await] JSXAttributeListElement[Yield, Await] : JSXAttribute[?Yield, ?Await] JSXSpreadAttribute[?Yield, ?Await] JSXSpreadAttribute[Yield, Await] : { ... AssignmentExpression[?Yield, ?Await] } JSXAttribute[Yield, Await] : JSXAttributeName JSXAttributeInitializer[?Yield, ?Await]opt JSXAttributeName : JSXIdentifierName JSXNamespacedName JSXAttributeInitializer[Yield, Await] : = JSXAttributeValue[?Yield, ?Await] JSXAttributeValue[Yield, Await] : JSXStringLiteral { AssignmentExpression[?Yield, ?Await] } JSXElement[?Yield, ?Await] JSXFragment[?Yield, ?Await] Note

Actual parsers implement these rules in various ways.

13.5.1 Static Semantics: Early Errors

JSXSpreadAttribute[Yield, Await] : { ... AssignmentExpression[?Yield, ?Await] } JSXAttributeValue[Yield, Await] : { AssignmentExpression[?Yield, ?Await] }

13.6 JSX Children

JSXChildren[Yield, Await] : JSXChild[?Yield, ?Await] JSXChildren[?Yield, ?Await] JSXChild[?Yield, ?Await] JSXChild[Yield, Await] : JSXText { } { AssignmentExpression[?Yield, ?Await] } { ... AssignmentExpression[?Yield, ?Await] } JSXElement[?Yield, ?Await] JSXFragment[?Yield, ?Await] Note 1

Ordinary JavaScript comments cannot appear as part of JSXChildren, as described in 8.2.2.

JSXChild : { } yields no children, thus can be used to embed comments in the children like {/* comment */}.

The production can also be used to split two text nodes, like <div>foo{}bar</div>.

Note 2

Actual parsers implement these rules in various ways.

  • Babel and SWC allow Expressions (comma operators) in { } or { ... }.

13.6.1 Static Semantics: Early Errors

JSXChild[Yield, Await] : { AssignmentExpression[?Yield, ?Await] } { ... AssignmentExpression[?Yield, ?Await] }

14 Error Handling and Language Extensions

This section extends Error Handling and Language Extensions.

14.1 Forbidden Extensions

This subclause extends Forbidden Extensions.

ECMAScript forbids extension of the Syntactic Grammar in a way that allows the token : is allowed to immediately follow BindingIdentifier. This restriction is only applied when [[TypeScript]] of the current syntax context is false.

Note

This relaxation will not invalidate the original specification's intent, as TypeScript code is not intended to be directly executed in the standard Web environment.

Annex A (normative) Named Character References

JSXNamedCharacterReferenceName :: one of AElig Aacute Acirc Agrave Alpha Aring Atilde Auml Beta Ccedil Chi Dagger Delta ETH Eacute Ecirc Egrave Epsilon Eta Euml Gamma Iacute Icirc Igrave Iota Iuml Kappa Lambda Mu Ntilde Nu OElig Oacute Ocirc Ograve Omega Omicron Oslash Otilde Ouml Phi Pi Prime Psi Rho Scaron Sigma THORN Tau Theta Uacute Ucirc Ugrave Upsilon Uuml Xi Yacute Yuml Zeta aacute acirc acute aelig agrave alefsym alpha amp and ang apos aring asymp atilde auml bdquo beta brvbar bull cap ccedil cedil cent chi circ clubs cong copy crarr cup curren dArr dagger darr deg delta diams divide eacute ecirc egrave empty emsp ensp epsilon equiv eta eth euml euro exist fnof forall frac12 frac14 frac34 frasl gamma ge gt hArr harr hearts hellip iacute icirc iexcl igrave image infin int iota iquest isin iuml kappa lArr lambda lang laquo larr lceil ldquo le lfloor lowast loz lrm lsaquo lsquo lt macr mdash micro middot minus mu nabla nbsp ndash ne ni not notin nsub ntilde nu oacute ocirc oelig ograve oline omega omicron oplus or ordf ordm oslash otilde otimes ouml para part permil perp phi pi piv plusmn pound prime prod prop psi quot rArr radic rang raquo rarr rceil rdquo real reg rfloor rho rlm rsaquo rsquo sbquo scaron sdot sect shy sigma sigmaf sim spades sub sube sum sup1 sup2 sup3 sup supe szlig tau there4 theta thetasym thinsp thorn tilde times trade uArr uacute uarr ucirc ugrave uml upsih upsilon uuml weierp xi yacute yen yuml zeta zwj zwnj Note

There are 253 available named character references total.

Among these, 252 are those listed by HTML 4.01 Specification. The remaining one is &apos; for ASCII single quote.

Those that were later added in HTML Living Standard, except for &apos;, are not included.

A.1 Static Semantics: SV

The SV of the production JSXNamedCharacterReference : & JSXNamedCharacterReferenceName ; is defined from the following mapping using the source text matched by JSXNamedCharacterReferenceName as the key:

Table 13: Mapping for SV of JSXNamedCharacterReference
Name SV
AElig U+00C6
AacuteU+00C1
AcircU+00C2
AgraveU+00C0
AlphaU+0391
AringU+00C5
AtildeU+00C3
AumlU+00C4
BetaU+0392
CcedilU+00C7
ChiU+03A7
DaggerU+2021
DeltaU+0394
ETHU+00D0
EacuteU+00C9
EcircU+00CA
EgraveU+00C8
EpsilonU+0395
EtaU+0397
EumlU+00CB
GammaU+0393
IacuteU+00CD
IcircU+00CE
IgraveU+00CC
IotaU+0399
IumlU+00CF
KappaU+039A
LambdaU+039B
MuU+039C
NtildeU+00D1
NuU+039D
OEligU+0152
OacuteU+00D3
OcircU+00D4
OgraveU+00D2
OmegaU+03A9
OmicronU+039F
OslashU+00D8
OtildeU+00D5
OumlU+00D6
PhiU+03A6
PiU+03A0
PrimeU+2033
PsiU+03A8
RhoU+03A1
ScaronU+0160
SigmaU+03A3
THORNU+00DE
TauU+03A4
ThetaU+0398
UacuteU+00DA
UcircU+00DB
UgraveU+00D9
UpsilonU+03A5
UumlU+00DC
XiU+039E
YacuteU+00DD
YumlU+0178
ZetaU+0396
aacuteU+00E1
acircU+00E2
acuteU+00B4
aeligU+00E6
agraveU+00E0
alefsymU+2135
alphaU+03B1
ampU+0026
andU+2227
angU+2220
aposU+0027
aringU+00E5
asympU+2248
atildeU+00E3
aumlU+00E4
bdquoU+201E
betaU+03B2
brvbarU+00A6
bullU+2022
capU+2229
ccedilU+00E7
cedilU+00B8
centU+00A2
chiU+03C7
circU+02C6
clubsU+2663
congU+2245
copyU+00A9
crarrU+21B5
cupU+222A
currenU+00A4
dArrU+21D3
daggerU+2020
darrU+2193
degU+00B0
deltaU+03B4
diamsU+2666
divideU+00F7
eacuteU+00E9
ecircU+00EA
egraveU+00E8
emptyU+2205
emspU+2003
enspU+2002
epsilonU+03B5
equivU+2261
etaU+03B7
ethU+00F0
eumlU+00EB
euroU+20AC
existU+2203
fnofU+0192
forallU+2200
frac12U+00BD
frac14U+00BC
frac34U+00BE
fraslU+2044
gammaU+03B3
geU+2265
gtU+003E
hArrU+21D4
harrU+2194
heartsU+2665
hellipU+2026
iacuteU+00ED
icircU+00EE
iexclU+00A1
igraveU+00EC
imageU+2111
infinU+221E
intU+222B
iotaU+03B9
iquestU+00BF
isinU+2208
iumlU+00EF
kappaU+03BA
lArrU+21D0
lambdaU+03BB
langU+2329
laquoU+00AB
larrU+2190
lceilU+2308
ldquoU+201C
leU+2264
lfloorU+230A
lowastU+2217
lozU+25CA
lrmU+200E
lsaquoU+2039
lsquoU+2018
ltU+003C
macrU+00AF
mdashU+2014
microU+00B5
middotU+00B7
minusU+2212
muU+03BC
nablaU+2207
nbspU+00A0
ndashU+2013
neU+2260
niU+220B
notU+00AC
notinU+2209
nsubU+2284
ntildeU+00F1
nuU+03BD
oacuteU+00F3
ocircU+00F4
oeligU+0153
ograveU+00F2
olineU+203E
omegaU+03C9
omicronU+03BF
oplusU+2295
orU+2228
ordfU+00AA
ordmU+00BA
oslashU+00F8
otildeU+00F5
otimesU+2297
oumlU+00F6
paraU+00B6
partU+2202
permilU+2030
perpU+22A5
phiU+03C6
piU+03C0
pivU+03D6
plusmnU+00B1
poundU+00A3
primeU+2032
prodU+220F
propU+221D
psiU+03C8
quotU+0022
rArrU+21D2
radicU+221A
rangU+232A
raquoU+00BB
rarrU+2192
rceilU+2309
rdquoU+201D
realU+211C
regU+00AE
rfloorU+230B
rhoU+03C1
rlmU+200F
rsaquoU+203A
rsquoU+2019
sbquoU+201A
scaronU+0161
sdotU+22C5
sectU+00A7
shyU+00AD
sigmaU+03C3
sigmafU+03C2
simU+223C
spadesU+2660
subU+2282
subeU+2286
sumU+2211
sup1U+00B9
sup2U+00B2
sup3U+00B3
supU+2283
supeU+2287
szligU+00DF
tauU+03C4
there4U+2234
thetaU+03B8
thetasymU+03D1
thinspU+2009
thornU+00FE
tildeU+02DC
timesU+00D7
tradeU+2122
uArrU+21D1
uacuteU+00FA
uarrU+2191
ucircU+00FB
ugraveU+00F9
umlU+00A8
upsihU+03D2
upsilonU+03C5
uumlU+00FC
weierpU+2118
xiU+03BE
yacuteU+00FD
yenU+00A5
yumlU+00FF
zetaU+03B6
zwjU+200D
zwnjU+200C

Annex B (informative) TypeScript Permissive Grammars

TSC parser is permissive so that it always consumes all input, even if it contains syntax errors.

It affects the way TypeScript handles ExpressionTypeArguments because permissive parsing inhibits backtracking in some cases.

B.1 Tokens

PermColon : : [lookahead ≠ :] PermOpenParen : ( [lookahead ≠ (] PermCloseParen : ) [lookahead ≠ )] PermOpenBrace : { [lookahead ≠ {] PermCloseBrace : } [lookahead ≠ }] PermIdentifierName : IdentifierName [lookahead ≠ IdentifierName] PermIdentifierNameAfterDot : [no LineTerminator here] IdentifierName [lookahead ≠ [no LineTerminator here] IdentifierName] [lookahead ≠ IdentifierName [no LineTerminator here] IdentifierName] IdentifierName [lookahead ≠ [no LineTerminator here] IdentifierName] [lookahead = IdentifierName [no LineTerminator here] IdentifierName] [lookahead ≠ IdentifierName] PermIdentifierNameOrPrivate : IdentifierName PrivateIdentifier [lookahead ∉ { IdentifierName, PrivateIdentifier }] PermIdentifier[Yield, Await] : [lookahead ≠ ReservedWord] IdentifierName [~Yield] yield [~Await] await PrivateIdentifier [+Yield] [lookahead = yield] [+Await] [lookahead = await] [lookahead ∉ { yield, await }] [lookahead = ReservedWord] [lookahead ∉ { IdentifierName, PrivateIdentifier }]

B.2 Primary Types

PermPrimaryType[Yield, Await] : [lookahead = IdentifierName] [lookahead ∉ { typeof, null, true, false, this, void, ExtraKeywordType, function, asserts [no LineTerminator here] IdentifierName }] PermTypeReference[?Yield, ?Await] [lookahead = ExtraKeywordType .] PermTypeReference[?Yield, ?Await] [lookahead = .] PermTypeReference[?Yield, ?Await] PermTypeQuery[?Yield, ?Await] KeywordType LiteralType [lookahead ∉ { this [no LineTerminator here] is }] this PermTupleType[?Yield, ?Await] ObjectType[?Yield, ?Await] MappedType[?Yield, ?Await] TemplateLiteralType[?Yield, ?Await] ( PermType[?Yield, ?Await] PermCloseParen [lookahead ≠ =>] PermJSDocAnyType PermJSDocPrefixNullableType[?Yield, ?Await] PermJSDocPrefixNonNullableType[?Yield, ?Await] PermJSDocFunctionType[?Yield, ?Await] this [no LineTerminator here] is PermType[?Yield, ?Await] asserts [no LineTerminator here] IdentifierName is PermType[?Yield, ?Await] asserts [no LineTerminator here] IdentifierName [lookahead ≠ is] [lookahead ∉ { IdentifierName, StringLiteral, NoSubstitutionTemplate, TemplateHead, NumericLiteral, - NumericLiteral, [, {, (, *, ?, !, . }] PermTypeReference[Yield, Await] : PermQualifiedTypeName[?Yield, ?Await] [lookahead ∉ { ., [no LineTerminator here] < }] PermQualifiedTypeName[?Yield, ?Await] [no LineTerminator here] PermTypeArguments[?Yield, ?Await] PermQualifiedTypeName[Yield, Await] : [lookahead ≠ import] PermIdentifierNameOrPrivate PermTypeImportCall[?Yield, ?Await] [lookahead ≠ .] PermTypeImportCall[?Yield, ?Await] . PermIdentifierNameOrPrivate PermQualifiedTypeName[?Yield, ?Await] . PermIdentifierNameAfterDot . PermIdentifierNameAfterDot PermTypeQuery[Yield, Await] : typeof PermExpressionInTypeQuery[?Yield, ?Await] [lookahead ∉ { ., [no LineTerminator here] < }] typeof PermExpressionInTypeQuery[?Yield, ?Await] [no LineTerminator here] PermTypeArguments[?Yield, ?Await] PermExpressionInTypeQuery[Yield, Await] : [lookahead ≠ import] PermIdentifierNameOrPrivate PermTypeImportCall[?Yield, ?Await] [lookahead ≠ .] PermTypeImportCall[?Yield, ?Await] . PermIdentifierNameOrPrivate PermExpressionInTypeQuery[?Yield, ?Await] . PermIdentifierNameAfterDot [lookahead ≠ IdentifierName] PermTypeImportCall[Yield, Await] : import PermOpenParen Type[?Yield, ?Await] PermCloseParen import PermOpenParen Type[?Yield, ?Await] , PermOpenBrace PermWithOrAsserts PermColon WithClauseBody ,opt PermCloseBrace PermCloseParen PermWithOrAsserts : with asserts [lookahead ∉ { with, asserts }] WithClauseBody : { WithEntries ,opt PermCloseBrace [lookahead ≠ {] PermTupleType[Yield, Await] : [ PermCloseTupleType [ PermTupleTypeElements[?Yield, ?Await] PermCloseTupleType2 [ PermTupleTypeElements[?Yield, ?Await] , PermCloseTupleType PermCloseTupleType : ] [lookahead ∉ { ], , }] PermCloseTupleType2 : ] [lookahead ∉ { ], , }] PermTupleTypeElements[Yield, Await] : PermTupleTypeElement[?Yield, ?Await] PermTupleTypeElements[?Yield, ?Await] , PermTupleTypeElement[?Yield, ?Await] PermTupleTypeElement[Yield, Await] : [lookahead ∉ { IdentifierName ?, IdentifierName :, ... }] Type[?Yield, ?Await] IdentifierName : Type[?Yield, ?Await] IdentifierName ? PermColon Type[?Yield, ?Await] ... [lookahead ∉ { IdentifierName ?, IdentifierName : }] Type[?Yield, ?Await] ... IdentifierName : Type[?Yield, ?Await] ... IdentifierName ? PermColon Type[?Yield, ?Await] [lookahead = ,] PermJSDocAnyType : * ? [lookahead ∈ { ,, }, ), >, =, | }] PermJSDocPrefixNullableType[Yield, Await] : ? [lookahead ∉ { ,, }, ), >, =, | }] PermType[?Yield, ?Await] PermJSDocPrefixNonNullableType[Yield, Await] : ! PermType[?Yield, ?Await] PermJSDocFunctionType[Yield, Await] : function [lookahead ≠ (] function ( PermJSDocFunctionParameters[?Yield, ?Await] ) PermReturnTypeAnnotation[?Yield, ?Await]opt PermJSDocFunctionParameters[Yield, Await] : [empty] PermJSDocFunctionParameterList[?Yield, ?Await] PermJSDocFunctionParameterList[?Yield, ?Await] , PermJSDocFunctionParameterList[Yield, Await] : PermJSDocFunctionParameter[?Yield, ?Await] PermJSDocFunctionParameterList[?Yield, ?Await] , PermJSDocFunctionParameter[?Yield, ?Await] PermJSDocFunctionParameter[Yield, Await] : this PermColon PermJSDocType[?Yield, ?Await] new PermColon PermJSDocType[?Yield, ?Await] PermJSDocType[?Yield, ?Await] PermJSDocType[Yield, Await] : Type[?Yield, ?Await] ... Type[?Yield, ?Await] Type[?Yield, ?Await] = ... Type[?Yield, ?Await] = Note

In PermTupleTypeElement, we don't account for ? after Type because in the permissive grammar, ? would first be interpreted as part of a permissive optional type.

B.3 Postfix Types

PermPostfixType[Yield, Await] : PermPrimaryType[?Yield, ?Await] PermPostfixType[?Yield, ?Await] [ ] PermPostfixType[?Yield, ?Await] [ Type[?Yield, ?Await] ]

B.4 Prefix Types

PermPrefixType[Yield, Await, Cond] : PermPostfixType[?Yield, ?Await] infer PermIdentifier[?Yield, ?Await] [lookahead ≠ extends] [~Cond] infer PermIdentifier[?Yield, ?Await] extends PermType[?Yield, ?Await] [+Cond] infer PermIdentifier[?Yield, ?Await] [lookahead = extends PermType[?Yield, ?Await] [lookahead = ?]] [+Cond] infer PermIdentifier[?Yield, ?Await] extends PermType[?Yield, ?Await] [lookahead ≠ ?] keyof PermPrefixType[?Yield, ?Await, ?Cond] readonly PermPrefixType[?Yield, ?Await, ?Cond] unique PermPrefixType[?Yield, ?Await, ?Cond] Note 1

In the main grammar, unique is restricted to unique symbol in VariableTypeAnnotation, but TSC parses it as a general prefix type operator at higher precedence and validates later.

Note 2

The infer ... extends constraint uses PermType, which always enables conditional types internally. This matches the main grammar where InferType uses Type[+Cond] for the constraint.

TSC disambiguates infer T extends Constraint from conditional types as follows: it greedily parses the constraint (with disallowConditionalTypesAnd), then checks whether ? follows. If conditional types are enabled in the outer context and ? follows, TSC backtracks and discards the constraint, so the extends belongs to the enclosing conditional type instead. If conditional types are disabled ([~Cond]), the constraint is always kept.

The four infer alternatives each represent a distinct case:

  • infer T [lookahead != extends] — bare infer when extends does not follow. Available in both [+Cond] and [~Cond].
  • [~Cond] infer T extends Constraint — constrained infer. TSC always keeps the constraint when conditional types are disabled.
  • [+Cond] infer T [lookahead = extends Constraint ?] — bare infer when extends Constraint ? follows. This models TSC's backtrack: TSC greedily parses the constraint, finds ? after it, and discards the constraint. The bare infer T then becomes part of the check type of the enclosing PermConditionalType. This alternative is not available in [~Cond] because TSC never backtracks when conditional types are disabled.
  • [+Cond] infer T extends Constraint [lookahead != ?] — constrained infer when ? does not follow the constraint. TSC keeps the constraint in this case.

In [~Cond] context, [lookahead != extends] and extends make the two alternatives mutually exclusive.

In [+Cond] context, the complex lookahead on the bare alternative and [lookahead != ?] on the constrained alternative partition the extends-follows cases by whether ? follows the constraint, making all three [+Cond] alternatives mutually exclusive.

B.5 Intersection Types

PermIntersectionType[Yield, Await, Cond] : PermPrefixType[?Yield, ?Await, ?Cond] & PermPrefixType[?Yield, ?Await, ?Cond] PermIntersectionType[?Yield, ?Await, ?Cond] & PermPrefixType[?Yield, ?Await, ?Cond]

B.6 Union Types

PermUnionType[Yield, Await, Cond] : PermIntersectionType[?Yield, ?Await, ?Cond] | PermIntersectionType[?Yield, ?Await, ?Cond] PermUnionType[?Yield, ?Await, ?Cond] | PermIntersectionType[?Yield, ?Await, ?Cond]

B.7 Conditional and Function Types

PermType[Yield, Await] : PermCondLevelType[?Yield, ?Await, +Cond] PermCondLevelType[Yield, Await, Cond] : [lookahead ∉ { <, new, abstract new }] PermUnionType[?Yield, ?Await, ?Cond] [lookahead ∉ { [no LineTerminator here] extends, [no LineTerminator here] is }] PermUnionType[?Yield, ?Await, ?Cond] [no LineTerminator here] is PermType[?Yield, ?Await] [+Cond] PermConditionalType[?Yield, ?Await, ?Cond] PermFunctionType[?Yield, ?Await, ?Cond] PermConstructorType[?Yield, ?Await, ?Cond] PermFunctionType[Yield, Await, Cond] : PermTypeParameters[?Yield, ?Await] ( FormalParameters[?Yield, ?Await] ) => PermType[?Yield, ?Await] ( FormalParameters[?Yield, ?Await] ) => PermType[?Yield, ?Await] PermTypeParameters[?Yield, ?Await] [lookahead ≠ (] PermConstructorType[Yield, Await, Cond] : abstractopt new PermTypeParameters[?Yield, ?Await] ( FormalParameters[?Yield, ?Await] ) => PermType[?Yield, ?Await] abstractopt new ( FormalParameters[?Yield, ?Await] ) => PermType[?Yield, ?Await] abstractopt new PermTypeParameters[?Yield, ?Await] [lookahead ≠ (] abstractopt new [lookahead ∉ { (, [no LineTerminator here] < }] PermTypeParameters[Yield, Await] : < PermTypeArgumentList[?Yield, ?Await] > < PermTypeArgumentList[?Yield, ?Await] , > < PermTypeArgumentList[?Yield, ?Await] [lookahead ∉ { >, , }] < PermTypeArgumentList[?Yield, ?Await] , [lookahead ∉ { >, , }] PermConditionalType[Yield, Await, Cond] : PermUnionType[?Yield, ?Await, ?Cond] [no LineTerminator here] extends PermCondLevelType[?Yield, ?Await, ~Cond] ? PermCondLevelType[?Yield, ?Await, +Cond] : PermCondLevelType[?Yield, ?Await, +Cond] Note 1

In the main grammar, asserts and this is type predicates only appear in ReturnTypeAnnotation. TSC parses them at the primary type level everywhere and validates their position later. TSC also allows newlines between asserts x / asserts this and is (see B.2).

Note 2

In the main grammar, x is type predicates only appear in ReturnTypeAnnotation. This permissive grammar models them at the PermType level for simplicity. TSC only parses them in return type context (via speculative parsing of identifier [no LineTerminator here] is).

Note 3

TSC always parses < as starting a function type, new as starting a constructor type, and abstract new as starting a constructor type in type position. The lookahead restriction on the first PermCondLevelType alternative prevents PermUnionType from matching in these cases. PermFunctionType and PermConstructorType use PermTypeParameters (with error recovery for missing >) and fallback alternatives to ensure they always match some prefix when their starting tokens are present.

Note 4

TSC determines whether ( starts a function type by checking whether the parenthesized content looks like formal parameters (e.g. (), (..., (x:, (x,, (x?, (x=, or (x) =>). The [lookahead != `=>`] restriction on the grouped type ( PermType ) in PermPrimaryType prevents ambiguity with PermFunctionType when => follows the closing parenthesis. The grouped type uses PermCloseParen to handle missing ).

B.8 Type Annotations

PermReturnTypeAnnotation[Yield, Await] : : PermType[?Yield, ?Await]

B.9 Type Arguments

PermTypeArguments[Yield, Await] : < PermTypeArgumentList[?Yield, ?Await] > < PermTypeArgumentList[?Yield, ?Await] , > PermTypeArgumentList[Yield, Await] : PermType[?Yield, ?Await] PermTypeArgumentList[?Yield, ?Await] , PermType[?Yield, ?Await]

Bibliography

  1. ECMA-262, ECMAScript® Language Specification, available at <https://tc39.es/ecma262/>
  2. TypeScript Documentation, available at <https://www.typescriptlang.org/docs/>

Colophon

This specification is authored on GitHub in a plaintext source format called Ecmarkup. Ecmarkup is an HTML and Markdown dialect that provides a framework and toolset for authoring ECMAScript specifications in plaintext and processing the specification into a full-featured HTML rendering that follows the editorial conventions for this document. Ecmarkup builds on and integrates a number of other formats and technologies including Grammarkdown for defining syntax and Ecmarkdown for authoring algorithm steps. PDF renderings of this specification are produced by printing the HTML rendering to a PDF.