TypeScript uses JavaScript’s tokens: the same comments, identifiers, numeric, string and template literals, and operators, which are described on the JavaScript lexical structure page. This page covers what TypeScript adds. It adds very few tokens. Most of the new syntax comes from new meanings for existing punctuation and from words that are keywords only in certain places.
Keywords
Every JavaScript reserved word stays reserved. TypeScript adds no reserved words of its own. Its keywords are contextual: outside the positions below they are ordinary identifiers, except for the few names that cannot be types.
| Word | Is a keyword where | See |
|---|---|---|
any unknown never string number boolean bigint symbol object undefined | In a type position, as a type name | Types |
type | Starting a type alias; in import type and export type | Interfaces and aliases |
keyof unique readonly | As type operators; readonly also on properties | Type operators |
infer | In the extends clause of a conditional type | Conditional types |
is asserts | In type predicates and assertion signatures | Narrowing |
as satisfies | As binary operators after an expression; as also in imports and exports, and in mapped types | Narrowing |
out | On a type parameter (in is the reserved word used beside it) | Generics |
abstract override declare accessor | As modifiers on classes and their members | Classes |
declare | Starting an ambient declaration | Declaration files |
namespace global | Starting a namespace block or a global augmentation | Namespaces |
module | In declare module "name". As a synonym for namespace it was removed in 7.0 | Ambient modules |
require | In import x = require("y") | Modules |
intrinsic | As the body of a compiler-provided type alias in the standard library |
interface, implements, private,
protected, public, package, let,
static and yield are reserved by JavaScript in strict mode only,
and TypeScript gives the first five their meaning.
async, await, of, get,
set, from, constructor, using and
defer come from JavaScript itself.
Names that cannot be types
An interface, type alias, class or
enum may not be named any, unknown,
never, number, bigint, boolean,
string, symbol, void, object or
undefined. They can still name variables, functions and namespaces.
let type = 1, of = 2, as = 3, keyof = 4, declare = 5; // all fine as variables
const string = "s"; // fine
type number = 1; // error: Type alias name cannot be 'number'
interface string {} // error: Interface name cannot be 'string'
Line breaks
Because the keywords are contextual, the parser looks at the next token, and a line break changes the result. A word followed by another name on the same line cannot be plain JavaScript, so that is what marks a declaration.
| Word | Starts a declaration only if |
|---|---|
type, interface | An identifier follows on the same line |
namespace, module | An identifier or string follows on the same line |
abstract, accessor, async, declare, public, protected, private, readonly | The next token is on the same line |
type
Alias = string; // the expression statement `type`, then an assignment to Alias
declare
function f(): void; // the expression statement `declare`, then a function with no body
The same applies to operators. as, satisfies and the postfix
non-null ! must be on the same line as the expression before them; on a
new line they begin something else.
Punctuation
No new operator tokens appear in expressions. Existing tokens take on these meanings:
| Token | TypeScript use |
|---|---|
: | A type annotation on a variable, parameter, property or return value |
? | An optional parameter, property or tuple element; the conditional type operator |
! | Postfix on an expression: not null. After a name in a declaration: definitely assigned |
< > | Type parameters and arguments |
=> | A function type |
| & | Union and intersection types. A leading one is allowed: type T = | A | B |
[ ] | Array, tuple, indexed access and index signature types |
... | A rest element in a tuple type |
- + | Before ? and readonly in a mapped type. - also makes a negative literal type: -1, -10n. There is no +1 type |
@ | Decorators |
Template literal syntax can also appear in a type: see template literal types.
Generics and comparisons
In an expression, < could be a comparison or the start of type
arguments, and the parser decides by trying the type arguments first. It scans
> one character at a time inside type arguments, so
Map<string, Array<number>> needs no space. Inside an expression it then
joins the characters back into >> or >= if needed. The attempt
succeeds if the text parses as types, ends with >, and the token after it
allows type arguments:
After the > | Result |
|---|---|
( or a template literal | Type arguments: a call or tagged template |
<, >, +, - | A comparison |
| A line break, a binary operator, or a token that cannot start an expression | Type arguments: an instantiation expression |
| Any other token that can start an expression | A comparison |
f(a<b, c>(d)); // ONE argument: calls a with type arguments b and c
f(a < b, c > (d)); // in JavaScript this would be two comparisons,
// but spaces do not change how TypeScript parses it
f((a < b), c > (d)); // parentheses make it two comparisons
const g = a < b > c; // comparisons: c can start an expression
Writing f<T>.x is an error, since an instantiation expression cannot be
followed by a property access. f<T>?.() is allowed.
In a .js file the type-argument attempt is skipped entirely.
Angle brackets at the start of an expression
A < where an expression is expected starts a type assertion, a generic
arrow function or JSX, depending on the file.
| Text | .ts | .tsx | .mts, .cts |
|---|---|---|---|
<string>x | Type assertion | JSX element | Reserved: an error up to 6.0, a type assertion in 7.0 |
<T>(x: T) => x | Generic arrow | JSX element | Reserved: an error |
<T,>(x: T) => x | Generic arrow | Generic arrow | Generic arrow |
<T extends object>(x: T) => x | Generic arrow | Generic arrow | Generic arrow |
Use as for assertions in every file, so that code can move between
extensions unchanged.
Differences in .tsx files
A .tsx file has the same tokens plus JSX. Where an expression can start,
< opens a JSX element. Inside an element the text follows
JSX rules instead of JavaScript’s:
- Text between tags is not tokenised as code. HTML entities such as
&are decoded. {starts an embedded expression. A literal>or}in text is an error; write{"}"}or>.- Attribute names may contain hyphens, as in
data-id, and a namespace prefix, as ina:b(5.1). - A generic component takes type arguments directly:
<List<string> items={names} />.
Comments and JSDoc
Comments are JavaScript’s. The compiler also reads
directive comments.
In TypeScript files, a /** */ comment documents a declaration for editors,
but the types in JSDoc tags are not used, so @param {number} x has no effect.
@deprecated is shown by editors, and @internal works with
stripInternal to leave a member out of declaration files.
Literals
Numeric, string, template, regular expression and BigInt literals are JavaScript’s. Since
5.5 the compiler checks the syntax of regular expression literals, and reports an unknown
group or a flag unavailable in the target; strings passed to
new RegExp() are not checked. Literals may also be used as
types.