A TypeScript file is JavaScript source with type syntax added. It is plain text with
no header. The extension says how the compiler parses it and what it writes, and a
project’s tsconfig.json says which files belong together. The syntax that
TypeScript shares with JavaScript is described on the
JavaScript file structure page.
Encoding and shape
The compiler reads a file as UTF-8 unless a byte order mark says otherwise. It accepts
the UTF-8 mark and the UTF-16 big-endian and little-endian marks. The mark is not
copied into the output unless emitBOM is set. Output line endings follow
newLine, which is lf or crlf.
A file may start with a #! line, which the compiler keeps as the first
line of the JavaScript it writes. Everything else is read in order:
SourceFile:
[Hashbang] {Comment | TripleSlashDirective} {Statement}
Statement:
any JavaScript statement
InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration
NamespaceDeclaration | AmbientDeclaration
ImportEqualsDeclaration | ExportAssignment | NamespaceExportDeclaration
The grammar blocks on these pages are informal summaries of what the compiler
accepts. The extra statements are covered on their own pages:
interfaces and aliases,
enums,
namespaces, import = and
export =, and ambient
declarations.
The extensions
| Extension | Holds | Compiler writes | Module format under node16 and later |
|---|---|---|---|
.ts | Code and types | .js, and .d.ts with declaration | ES module if the nearest package.json has "type": "module", otherwise CommonJS |
.tsx | Code, types and JSX | .js, or .jsx with jsx: preserve; .d.ts | As for .ts |
.mts | Code and types | .mjs, .d.mts | Always ES module |
.cts | Code and types | .cjs, .d.cts | Always CommonJS |
.d.ts | Declarations only | Nothing | As for .ts |
.d.mts, .d.cts | Declarations for a .mjs or .cjs file | Nothing | ES module, CommonJS |
.d.x.ts | Declarations for a non-JavaScript file, such as app.d.css.ts for app.css, with allowArbitraryExtensions (5.0) | Nothing | Not applicable |
With allowJs the compiler also reads .js, .jsx,
.mjs and .cjs. With resolveJsonModule it reads
.json imports.
Syntax differences
The extension changes how a few forms parse. See Lexical structure.
| Form | .ts | .tsx | .mts, .cts |
|---|---|---|---|
| JSX elements | No | Yes | No |
<T>value assertion | Yes | No, parsed as JSX | Reserved: an error up to 6.0, accepted by 7.0 |
<T>(x: T) => x generic arrow | Yes | No, parsed as JSX | Reserved: an error |
<T,>(x: T) => x or <T extends unknown>(x: T) => x | Yes | Yes | Yes |
Scripts and modules
A file is either a script, whose top-level names are global and shared with
every other script, or a module, which has its own scope. Two scripts that
both declare const x conflict. The moduleDetection option
decides which a file is.
| Value | A file is a module when |
|---|---|
auto | It has an import, an export or import.meta; or it uses JSX with jsx: react-jsx or react-jsxdev; or its format is ES module under module: node16 or later |
legacy | It has an import, an export or import.meta |
force | It is not a declaration file, or it has one of those forms |
When the option is not set, the default is force if module is
one of the Node.js modes and auto otherwise. In auto mode, a file
with nothing to import or export can write export {} to become a module.
The module format of the emitted code is a separate matter, covered in Modules and namespaces.
Triple-slash directives
A triple-slash directive is a single-line comment holding one XML tag. It works only at the top of a file, with nothing before it but comments and other directives. After the first statement it is an ordinary comment (Handbook: Triple-Slash Directives).
| Directive | Meaning |
|---|---|
/// <reference path="./x.d.ts" /> | Adds another file to the compilation. A relative path is resolved from this file. Ignored under noResolve |
/// <reference types="node" /> | Depends on a package of types, as @types/node. May add resolution-mode="import" or "require". In .ts files the types option is preferred |
/// <reference lib="es2017.string" /> | Includes a built-in library, named as in the lib option |
/// <reference no-default-lib="true" /> | No longer supported since 6.0. Use noLib or libReplacement |
/// <amd-module name="x" /> | Named an AMD module. Has no effect since 6.0, which dropped AMD output |
/// <amd-dependency path="x" /> | Deprecated. Use import "x"; |
Since 5.5 the compiler does not write these directives into its output unless they
carry preserve="true", and it no longer generates them in declaration
files.
/// <reference types="node" />
/// <reference lib="es2022" />
/// <reference path="./globals.d.ts" preserve="true" />
export const start = process.hrtime.bigint();
Comment directives
| Comment | Effect | Since |
|---|---|---|
// @ts-ignore | Hides errors on the next line | 2.6 |
// @ts-expect-error | Hides errors on the next line, and is itself an error if that line has none | 3.9 |
// @ts-nocheck | At the top of a file: reports no type errors in it | 3.7 in .ts |
// @ts-check | At the top of a JavaScript file: reports type errors in it | 2.3 |
Files with JSX can also set the factory per file with pragma comments.
tsconfig.json
A tsconfig.json file marks the root of a project. It is JSON that also
allows comments and trailing commas
(TSConfig reference). The compiler
looks for one in the working directory and then in each parent.
| Field | Meaning |
|---|---|
files | An explicit list of files |
include, exclude | Glob patterns that add and remove files. include defaults to everything under the folder, unless files is set |
extends | One or several base files whose settings are inherited (several since 5.0) |
references | Other projects this one depends on |
compilerOptions | The compiler options |
A file imported by a file in the project is part of the project even if
exclude matches it. In path fields, ${configDir} (5.5) stands for
the folder of the project’s own config file, which helps in shared base files.
Since 6.0, running tsc foo.ts in a folder that has a
tsconfig.json is an error, TS5112. tsc --ignoreConfig foo.ts
compiles the file with the command-line options alone.
{
"compilerOptions": {
"module": "nodenext",
"target": "esnext",
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"verbatimModuleSyntax": true
},
"include": ["src"]
}
src to distType erasure and emit
The compiler checks types and writes JavaScript, and the two steps are independent: by
default it writes the output even when the checks fail, unless
noEmitOnError is set. Types never affect the behaviour of the program.
Most TypeScript syntax is erased completely, while a few forms generate code.
| Source | Output |
|---|---|
Annotations, : T, <T>, this parameters, ? on parameters and properties | Removed |
interface, type, overload signatures, declare declarations | Removed |
as, satisfies, ! | Removed; the expression stays |
public, private, protected, readonly, abstract, override on members | Removed |
abstract methods and declare fields | Removed |
import type, export type | Removed |
An import used only as a type | Removed, unless verbatimModuleSyntax is set |
namespace holding only types | Removed |
const enum | Removed, and its uses replaced by the values, unless preserveConstEnums is set |
enum | Code: a variable and a function that fills it |
namespace with values | Code: a variable and a function that fills it |
| Parameter properties | Code: field declarations and assignments in the constructor |
| Legacy decorators | Code: calls to a helper after the class |
import x = require(), export = | Code: require and module.exports |
// Source
export enum Direction { Up, Down }
export class Point {
constructor(public x: number, private readonly y = 1) {}
}
const size = (input as unknown as number)!;
// Output with target es2022
export var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
})(Direction || (Direction = {}));
export class Point {
x;
y;
constructor(x, y = 1) {
this.x = x;
this.y = y;
}
}
const size = input;
The output also depends on target, which lowers newer JavaScript syntax
for older runtimes, and on module, which sets the import and export forms.
jsx controls how JSX is transformed.
With declaration the compiler also writes a
declaration file, and with
sourceMap a .js.map file.
Running without compiling
Tools that remove types without checking them, such as the type stripping in
Node.js, cannot generate the code in the table above. The
erasableSyntaxOnly option (5.8) makes the compiler reject those forms: an
enum, a namespace with runtime code, a parameter property,
and import = and export =. A tool that compiles one file at a
time also cannot see other files, and isolatedModules rejects code that
would need to. See Compiler
options.