2020-08-28

TypeScript - Emit Decorator Metadata - emitDecoratorMetadata

Emit Decorator Metadata - emitDecoratorMetadata

Enables experimental support for emitting type metadata for decorators which works with the module reflect-metadata.

For example, here is the JavaScript

function LogMethod(
  target: any,
  propertyKey: string | symbol,
  descriptor: PropertyDescriptor
) {
  console.log(target);
  console.log(propertyKey);
  console.log(descriptor);
}

class Demo {
  @LogMethod
  public foo(bar: number) {
    // do nothing
  }
}

const demo = new Demo();Try
With emitDecoratorMetadata not set to true (default):

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function LogMethod(target, propertyKey, descriptor) {
    console.log(target);
    console.log(propertyKey);
    console.log(descriptor);
}
class Demo {
    foo(bar) {
        // do nothing
    }
}
__decorate([
    LogMethod
], Demo.prototype, "foo", null);
const demo = new Demo();Try
With emitDecoratorMetadata set to true:

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
function LogMethod(target, propertyKey, descriptor) {
    console.log(target);
    console.log(propertyKey);
    console.log(descriptor);
}
class Demo {
    foo(bar) {
        // do nothing
    }
}
__decorate([
    LogMethod,
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Number]),
    __metadata("design:returntype", void 0)
], Demo.prototype, "foo", null);
const demo = new Demo();

TypeScript - (tsconfig) Linter Checks

#Linter Checks

A collection of extra checks, which somewhat cross the boundaries of compiler vs linter. You may prefer to use a tool like eslint over these options if you are looking for more in-depth rules.

# No Fallthrough Cases In Switch - noFallthroughCasesInSwitch
Report errors for fallthrough cases in switch statements. Ensures that any non-empty case inside a switch statement includes either break or return. This means you won’t accidentally ship a case fallthrough bug.

const a: number = 6;

switch (a) {
  case 0:
Fallthrough case in switch.
    console.log("even");
  case 1:
    console.log("odd");
    break;
}Try
Default:
false
Released:
1.8
# No Implicit Returns - noImplicitReturns
When enabled, TypeScript will check all code paths in a function to ensure they return a value.

function lookupHeadphonesManufacturer(color: "blue" | "black"): string {
Function lacks ending return statement and return type does not include 'undefined'.
  if (color === "blue") {
    return "beats";
  } else {
    "bose";
  }
}Try
Default:
false
Released:
1.8
# No Unused Locals - noUnusedLocals
Report errors on unused local variables.

const createKeyboard = (modelID: number) => {
  const defaultModelID = 23;
'defaultModelID' is declared but its value is never read.
  return { type: "keyboard", modelID };
};Try
Default:
false
Released:
2.0
# No Unused Parameters - noUnusedParameters
Report errors on unused parameters in functions.

const createDefaultKeyboard = (modelID: number) => {
'modelID' is declared but its value is never read.
  const defaultModelID = 23;
  return { type: "keyboard", modelID: defaultModelID };
};Try
Default:
false
Released:
2.0

TypeScript - (tsconfig) Source Maps

#Source Maps

In order to provide rich debugging tools and crash reports which make sense to developers, TypeScript supports emitting additional files which conform to the JavaScript Source Map standards.

These are emitted as .map files which live alongside the file they represent.

# Inline Source Map - inlineSourceMap
When set, instead of writing out a .js.map file to provide source maps, TypeScript will embed the source map content in the .js files. Although this results in larger JS files, it can be convenient in some scenarios. For example, you might want to debug JS files on a webserver that doesn’t allow .map files to be served.

Mutually exclusive with sourceMap.

For example, with this TypeScript:

const helloWorld = "hi";
console.log(helloWorld);
Converts to this JavaScript:

"use strict";
const helloWorld = "hi";
console.log(helloWorld);Try
Then enable building it with inlineSourceMap enabled there is a comment at the bottom of the file which includes a source-map for the file.

"use strict";
const helloWorld = "hi";
console.log(helloWorld);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDO0FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMifQ==Try
Default:
false
Released:
1.5
# Inline Sources - inlineSources
When set, TypeScript will include the original content of the .ts file as an embedded string in the source map. This is often useful in the same cases as inlineSourceMap.

Requires either sourceMap or inlineSourceMap to be set.

For example, with this TypeScript:

const helloWorld = "hi";
console.log(helloWorld);Try
By default converts to this JavaScript:

"use strict";
const helloWorld = "hi";
console.log(helloWorld);Try
Then enable building it with inlineSources and inlineSourceMap enabled there is a comment at the bottom of the file which includes a source-map for the file. Note that the end is different from the example in inlineSourceMap because the source-map now contains the original source code also.

"use strict";
const helloWorld = "hi";
console.log(helloWorld);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDO0FBQ3hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBoZWxsb1dvcmxkID0gXCJoaVwiO1xuY29uc29sZS5sb2coaGVsbG9Xb3JsZCk7Il19Try
Default:
false
Released:
1.5
# Map Root - mapRoot
Specify the location where debugger should locate map files instead of generated locations. This string is treated verbatim inside the source-map, for example:

{
  "compilerOptions": {
    "sourceMap": true,
    "mapRoot": "https://my-website.com/debug/sourcemaps/"
  }
}
Would declare that index.js will have sourcemaps at https://my-website.com/debug/sourcemaps/index.js.map.

# Source Root - sourceRoot
Specify the location where a debugger should locate TypeScript files instead of relative source locations. This string is treated verbatim inside the source-map where you can use a path or a URL:

{
  "compilerOptions": {
    "sourceMap": true,
    "sourceRoot": "https://my-website.com/debug/source/"
  }
}
Would declare that index.js will have a source file at https://my-website.com/debug/source/index.ts.

TypeScript - (tsconfig) Module Resolution

#Module Resolution

# Allow Synthetic Default Imports - allowSyntheticDefaultImports
When set to true, allowSyntheticDefaultImports allows you to write an import like:

import React from "react";
instead of:

import * as React from "react";
When the module does not explicitly specify a default export.

For example, without allowSyntheticDefaultImports as true:

// @filename: utilFunctions.js
Module '"utilFunctions"' can only be default-imported using the 'allowSyntheticDefaultImports' flag
const getStringLength = (str) => str.length;

module.exports = {
  getStringLength,
};

// @filename: index.ts
import utils from "./utilFunctions";

const count = utils.getStringLength("Check JS");Try
This code raises an error because there isn’t a default object which you can import. Even though it feels like it should. For convenience, transpilers like Babel will automatically create a default if one isn’t created. Making the module look a bit more like:

// @filename: utilFunctions.js
const getStringLength = (str) => str.length;
const allFunctions = {
  getStringLength,
};

module.exports = allFunctions;
module.exports.default = allFunctions;
This flag does not affect the JavaScript emitted by TypeScript, it only for the type checking. This option brings the behavior of TypeScript in-line with Babel, where extra code is emitted to make using a default export of a module more ergonomic.

Default:
module === "system" or esModuleInterop
Related:
esModuleInterop
Released:
1.8
# Allow Umd Global Access - allowUmdGlobalAccess
When set to true, allowUmdGlobalAccess lets you access UMD exports as globals from inside module files. A module file is a file that has imports and/or exports. Without this flag, using an export from a UMD module requires an import declaration.

An example use case for this flag would be a web project where you know the particular library (like jQuery or Lodash) will always be available at runtime, but you can’t access it with an import.

Default:
false
Released:
3.5
# Base Url - baseUrl
Lets you set a base directory to resolve non-absolute module names.

You can define a root folder where you can do absolute file resolution. E.g.

baseUrl
├── ex.ts
├── hello
│   └── world.ts
└── tsconfig.json
With "baseUrl": "./" inside this project TypeScript will look for files starting at the same folder as the tsconfig.json.

import { helloWorld } from "hello/world";

console.log(helloWorld);
If you get tired of imports always looking like "../" or "./". Or needing to change as you move files, this is a great way to fix that.

# ES Module Interop - esModuleInterop
By default (with esModuleInterop false or not set) TypeScript treats CommonJS/AMD/UMD modules similar to ES6 modules. In doing this, there are two parts in particular which turned out to be flawed assumptions:

a namespace import like import * as moment from "moment" acts the same as const moment = require("moment")
a default import like import moment as "moment" acts the same as const moment = require("moment").default
This mis-match causes these two issues:

the ES6 modules spec states that a namespace import (import * as x) can only be an object, by having TypeScript treating it the same as = require("x") then TypeScript allowed for the import to be treated as a function and be callable. This breaks the spec’s recommendations.
while accurate to the ES6 modules spec, most libraries with CommonJS/AMD/UMD modules didn’t conform as strictly as TypeScript’s implementation.
Turning on esModuleInterop will fix both of these problems in the code transpiled by TypeScript. The first changes the behavior in the compiler,the second is fixed by two new helper functions which provide a shim to ensure compatibility in the emitted JavaScript:

import * as fs from "fs";
import _ from "lodash";

fs.readFileSync("file.txt", "utf8");
_.chunk(["a", "b", "c", "d"], 2);
With esModuleInterop disabled:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const lodash_1 = require("lodash");
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);Try
With esModuleInterop set to true:

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs"));
const lodash_1 = __importDefault(require("lodash"));
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);Try
Note: You can make JS emit terser by enabling importHelpers:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const fs = tslib_1.__importStar(require("fs"));
const lodash_1 = tslib_1.__importDefault(require("lodash"));
fs.readFileSync("file.txt", "utf8");
lodash_1.default.chunk(["a", "b", "c", "d"], 2);Try
Enabling esModuleInterop will also enable allowSyntheticDefaultImports.

Recommended:
True
Default:
false
Related:
allowSyntheticDefaultImports
Released:
2.7
# Module Resolution - moduleResolution
Specify the module resolution strategy: 'node' (Node.js) or 'classic' (used in TypeScript before the release of 1.6). You probably won’t need to use classic in modern code.

There is a handbook reference page on Module Resolution

Default:
module === AMD, UMD, System or ES6 then Classic

Otherwise Node
Related:
module
# Paths - paths
A series of entries which re-map imports to lookup locations relative to the baseUrl, there is a larger coverage of paths in the handbook.

paths lets you declare how TypeScript should resolve an import in your require/imports.

{
  "compilerOptions": {
    "baseUrl": ".", // this must be specified if "paths" is specified.
    "paths": {
      "jquery": ["node_modules/jquery/dist/jquery"] // this mapping is relative to "baseUrl"
    }
  }
}
This would allow you to be able to write import "jquery", and get all of the correct typing locally.

{
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
        "app/*": ["app/*"],
        "config/*": ["app/_config/*"],
        "environment/*": ["environments/*"],
        "shared/*": ["app/_shared/*"],
        "helpers/*": ["helpers/*"],
        "tests/*": ["tests/*"]
    },
}
In this case, you can tell the TypeScript file resolver to support a number of custom prefixes to find code. This pattern can be used to avoid long relative paths within your codebase.

# Preserve Symlinks - preserveSymlinks
This is to reflect the same flag in Node.js; which does not resolve the real path of symlinks.

This flag also exhibits the opposite behavior to Webpack’s resolve.symlinks option (i.e. setting TypeScript’s preserveSymlinks to true parallels setting Webpack’s resolve.symlinks to false, and vice-versa).

With this enabled, references to modules and packages (e.g. imports and /// <reference type="..." /> directives) are all resolved relative to the location of the symbolic link file, rather than relative to the path that the symbolic link resolves to.

Default:
false
# Root Dirs - rootDirs
Using rootDirs, you can inform the compiler that there are many “virtual” directories acting as a single root. This allows the compiler to resolve relative module imports within these “virtual” directories, as if they were merged in to one directory.

For example:

 src
 └── views
     └── view1.ts (can import "./template1", "./view2`)
     └── view2.ts (can import "./template1", "./view1`)

 generated
 └── templates
         └── views
             └── template1.ts (can import "./view1", "./view2")
{
  "compilerOptions": {
    "rootDirs": ["src/views", "generated/templates/views"]
  }
}
This does not affect how TypeScript emits JavaScript, it only emulates the assumption that they will be able to work via those relative paths at runtime.

Released:
2.0
# Type Roots - typeRoots
By default all visible ”@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible. For example, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

If typeRoots is specified, only packages under typeRoots will be included. For example:

{
  "compilerOptions": {
    "typeRoots": ["./typings", "./vendor/types"]
  }
}
This config file will include all packages under ./typings and ./vendor/types, and no packages from ./node_modules/@types. All paths are relative to the tsconfig.json.

Related:
types
# Types - types
By default all visible ”@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible. For example, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

If types is specified, only packages listed will be included in the global scope. For instance:

{
  "compilerOptions": {
    "types": ["node", "jest", "express"]
  }
}
This tsconfig.json file will only include ./node_modules/@types/node, ./node_modules/@types/jest and ./node_modules/@types/express. Other packages under node_modules/@types/* will not be included.

What does this affect?
This option does not affect how @types/* are included in your application code, for example if you had the above compilerOptions example with code like:

import * as moment from "moment";

moment().format("MMMM Do YYYY, h:mm:ss a");
The moment import would be fully typed.

When you have this option set, by not including a module in the types array it:

Will not add globals to your project (e.g process in node, or expect in Jest)
Will not have exports appear as auto-import recommendations
This feature differs from typeRoots in that it is about specifying only the exact types you want included, whereas typeRoots supports saying you want particular folders.

Related:
typeRoots

TypeScript - (tsconfig) Strict Checks

#Strict Checks

We recommend using the compiler option strict to opt-in to every possible improvement as they are built.

TypeScript supports a wide spectrum of JavaScript patterns and defaults to allowing for quite a lot of flexibility in accommodating these styles. Often the safety and potential scalability of a codebase can be at odds with some of these techniques.

Because of the variety of supported JavaScript, upgrading to a new version of TypeScript can uncover two types of errors:

Errors which already exist in your codebase, which TypeScript has uncovered because the language has refined its understanding of JavaScript.
A new suite of errors which tackle a new problem domain.
TypeScript will usually add a compiler flag for the latter set of errors, and by default these are not enabled.

# Always Strict - alwaysStrict
Ensures that your files are parsed in the ECMAScript strict mode, and emit “use strict” for each source file.

ECMAScript strict mode was introduced in ES5 and provides behavior tweaks to the runtime of the JavaScript engine to improve performance, and makes a set of errors throw instead of silently ignoring them.

Default:
false, unless strict is set
Released:
2.1
# No Implicit Any - noImplicitAny
In some cases where no type annotations are present, TypeScript will fall back to a type of any for a variable when it cannot infer the type.

This can cause some errors to be missed, for example:

function fn(s) {
  // No error?
  console.log(s.subtr(3));
}
fn(42);Try
Turning on noImplicitAny however TypeScript will issue an error whenever it would have inferred any:

function fn(s) {
Parameter 's' implicitly has an 'any' type.
  console.log(s.subtr(3));
}Try
Recommended:
True
Default:
false, unless strict is set
# No Implicit This - noImplicitThis
Raise error on ‘this’ expressions with an implied ‘any’ type.

For example, the class below returns a function which tries to access this.width and this.height – but the context for this inside the function inside getAreaFunction is not the instance of the Rectangle.

class Rectangle {
  width: number;
  height: number;

  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  getAreaFunction() {
    return function () {
      return this.width * this.height;
'this' implicitly has type 'any' because it does not have a type annotation.
'this' implicitly has type 'any' because it does not have a type annotation.
    };
  }
}Try
Recommended:
True
Default:
false, unless strict is set
Released:
2.0
# Strict - strict
The strict flag enables a wide range of type checking behavior that results in stronger guarantees of program correctness. Turning this on is equivalent to enabling all of the strict mode family options, which are outlined below. You can then turn off individual strict mode family checks as needed.

Future versions of TypeScript may introduce additional stricter checking under this flag, so upgrades of TypeScript might result in new type errors in your program. When appropriate and possible, a corresponding flag will be added to disable that behavior.

Recommended:
True
Default:
false
Related:
strictBindCallApply, strictFunctionTypes, strictPropertyInitialization
Released:
2.3
# Strict Bind Call Apply - strictBindCallApply
When set, TypeScript will check that the built-in methods of functions call, bind, and apply are invoked with correct argument for the underlying function:

// With strictBindCallApply on
function fn(x: string) {
  return parseInt(x);
}

const n1 = fn.call(undefined, "10");

const n2 = fn.call(undefined, false);
Argument of type 'boolean' is not assignable to parameter of type 'string'.
Try
Otherwise, these functions accept any arguments and will return any:

// With strictBindCallApply off
function fn(x: string) {
  return parseInt(x);
}

// Note: No error; return type is 'any'
const n = fn.call(undefined, false);Try
Recommended:
True
Default:
false, unless strict is set
Released:
3.2
# Strict Function Types - strictFunctionTypes
When enabled, this flag causes functions parameters to be checked more correctly.

Here’s a basic example with strictFunctionTypes off:

function fn(x: string) {
  console.log("Hello, " + x.toLowerCase());
}

type StringOrNumberFunc = (ns: string | number) => void;

// Unsafe assignment
let func: StringOrNumberFunc = fn;
// Unsafe call - will crash
func(10);Try
With strictFunctionTypes on, the error is correctly detected:

function fn(x: string) {
  console.log("Hello, " + x.toLowerCase());
}

type StringOrNumberFunc = (ns: string | number) => void;

// Unsafe assignment is prevented
let func: StringOrNumberFunc = fn;
Type '(x: string) => void' is not assignable to type 'StringOrNumberFunc'.
  Types of parameters 'x' and 'ns' are incompatible.
    Type 'string | number' is not assignable to type 'string'.
      Type 'number' is not assignable to type 'string'.
Try
During development of this feature, we discovered a large number of inherently unsafe class hierarchies, including some in the DOM. Because of this, the setting only applies to functions written in function syntax, not to those in method syntax:

type Methodish = {
  func(x: string | number): void;
};

function fn(x: string) {
  console.log("Hello, " + x.toLowerCase());
}

// Ultimately an unsafe assignment, but not detected
const m: Methodish = {
  func: fn,
};
m.func(10);Try
Recommended:
True
Default:
false, unless strict is set
Released:
2.6
# Strict Null Checks - strictNullChecks
When strictNullChecks is false, null and undefined are effectively ignored by the language. This can lead to unexpected errors at runtime.

When strictNullChecks is true, null and undefined have their own distinct types and you’ll get a type error if you try to use them where a concrete value is expected.

For example with this TypeScript code, users.find has no guarantee that it will actually find a user, but you can write code as though it will:

declare const loggedInUsername: string;

const users = [
  { name: "Oby", age: 12 },
  { name: "Heera", age: 32 },
];

const loggedInUser = users.find((u) => u.name === loggedInUsername);
console.log(loggedInUser.age);Try
Setting strictNullChecks to true will raise an error that you have not made a guarantee that the loggedInUser exists before trying to use it.

declare const loggedInUsername: string;

const users = [
  { name: "Oby", age: 12 },
  { name: "Heera", age: 32 },
];

const loggedInUser = users.find((u) => u.name === loggedInUsername);
console.log(loggedInUser.age);
Object is possibly 'undefined'.
Try
The second example failed because the array’s find function looks a bit like this simplification:

// When strictNullChecks: true
type Array = {
  find(predicate: (value: any, index: number) => boolean): S | undefined;
};

// When strictNullChecks: false the undefined is removed from the type system,
// allowing you to write code which assumes it always found a result
type Array = {
  find(predicate: (value: any, index: number) => boolean): S;
};
Recommended:
True
Default:
false, unless strict is set
Released:
2.0
# Strict Property Initialization - strictPropertyInitialization
When set to true, TypeScript will raise an error when a class property was declared but not set in the constructor.

class UserAccount {
  name: string;
  accountType = "user";

  email: string;
Property 'email' has no initializer and is not definitely assigned in the constructor.
  address: string | undefined;

  constructor(name: string) {
    this.name = name;
    // Note that this.email is not set
  }
}Try
In the above case:

this.name is set specifically.
this.accountType is set by default.
this.email is not set and raises an error.
this.address is declared as potentially undefined which means it does not have to be set.
Default:
false, unless strict is set
Released:
2.7

TypeScript - (tsconfig) Project Options

#Project Options

These settings are used to define the runtime expectations of your project, how and where you want the JavaScript to be emitted and the level of integration you want with existing JavaScript code.

# Allow JS - allowJs
Allow JavaScript files to be imported inside your project, instead of just .ts and .tsx files. For example, this JS file:

// @filename: card.js
export const defaultCardDeck = "Heart";Try
When imported into a TypeScript file will raise an error:

// @filename: index.ts
import { defaultCardDeck } from "./card";

console.log(defaultCardDeck);Try
Imports fine with allowJs enabled:

// @filename: index.ts
import { defaultCardDeck } from "./card";

console.log(defaultCardDeck);Try
This flag can be used as a way to incrementally add TypeScript files into JS projects by allowing the .ts and .tsx files to live along-side existing JavaScript files.

Default:
false
Related:
checkJs, emitDeclarationOnly
Released:
1.8
# Check JS - checkJs
Works in tandem with allowJs. When checkJs is enabled then errors are reported in JavaScript files. This is the equivalent of including // @ts-check at the top of all JavaScript files which are included in your project.

For example, this is incorrect JavaScript according to the parseFloat type definition which comes with TypeScript:

// parseFloat only takes a string
module.exports.pi = parseFloat(3.124);
When imported into a TypeScript module:

// @filename: constants.js
module.exports.pi = parseFloat(3.124);

// @filename: index.ts
import { pi } from "./constants";
console.log(pi);Try
You will not get any errors. However, if you turn on checkJs then you will get error messages from the JavaScript file.

// @filename: constants.js
Argument of type 'number' is not assignable to parameter of type 'string'.
module.exports.pi = parseFloat(3.124);

// @filename: index.ts
import { pi } from "./constants";
console.log(pi);Try
Default:
false
Related:
allowJs, emitDeclarationOnly
# Composite - composite
The composite option enforces certain constraints which make it possible for build tools (including TypeScript itself, under --build mode) to quickly determine if a project has been built yet.

When this setting is on:

The rootDir setting, if not explicitly set, defaults to the directory containing the tsconfig.json file.
All implementation files must be matched by an include pattern or listed in the files array. If this constraint is violated, tsc will inform you which files weren’t specified.
declaration defaults to true
You can find documentation on TypeScript projects in the handbook.

Default:
true
Related:
incremental, tsBuildInfoFile
Released:
3.0
# Declaration - declaration
Generate .d.ts files for every TypeScript or JavaScript file inside your project. These .d.ts files are type definition files which describe the external API of your module. With .d.ts files, tools like TypeScript can provide intellisense and accurate types for un-typed code.

When declaration is set to true, running the compiler with this TypeScript code:

export let helloWorld = "hi";Try
Will generate an index.js file like this:

export let helloWorld = "hi";Try
With a corresponding helloWorld.d.ts:

export declare let helloWorld: string;Try
When working with .d.ts files for JavaScript files you may want to use emitDeclarationOnly or use outDir to ensure that the JavaScript files are not overwritten.

Default:
True when TS
Related:
emitDeclarationOnly
Released:
1.0
# Declaration Map - declarationMap
Generates a source map for .d.ts files which map back to the original .ts source file. This will allow editors such as VS Code to go to the original .ts file when using features like Go to Definition.

You should strongly consider turning this on if you’re using project references.

Default:
false
Released:
2.9
# Downlevel Iteration - downlevelIteration
Downleveling is TypeScript’s term for transpiling to an older version of JavaScript. This flag is to enable support for a more accurate implementation of how modern JavaScript iterates through new concepts in older JavaScript runtimes.

ECMAScript 6 added several new iteration primitives: the for / of loop (for (el of arr)), Array spread ([a, ...b]), argument spread (fn(...args)), and Symbol.iterator. --downlevelIteration allows for these iteration primitives to be used more accurately in ES5 environments if a Symbol.iterator implementation is present.

Example: Effects on for / of
Without downlevelIteration on, a for / of loop on any object is downleveled to a traditional for loop:

"use strict";
var str = "Hello!";
for (var _i = 0, str_1 = str; _i < str_1.length; _i++) {
    var s = str_1[_i];
    console.log(s);
}Try
This is often what people expect, but it’s not 100% compliant with ECMAScript 6 behavior. Certain strings, such as emoji (😜), have a .length of 2 (or even more!), but should iterate as 1 unit in a for-of loop. See this blog post by Jonathan New for a longer explanation.

When downlevelIteration is enabled, TypeScript will use a helper function that checks for a Symbol.iterator implementation (either native or polyfill). If this implementation is missing, you’ll fall back to index-based iteration.

"use strict";
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var e_1, _a;
var str = "Hello!";
try {
    for (var str_1 = __values(str), str_1_1 = str_1.next(); !str_1_1.done; str_1_1 = str_1.next()) {
        var s = str_1_1.value;
        console.log(s);
    }
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
    try {
        if (str_1_1 && !str_1_1.done && (_a = str_1.return)) _a.call(str_1);
    }
    finally { if (e_1) throw e_1.error; }
}Try
Note: enabling downlevelIteration does not improve compliance if Symbol.iterator is not present in the runtime.

Example: Effects on Array Spreads
This is an array spread:

// Make a new array who elements are 1 followed by the elements of arr2
const arr = [1, ...arr2];
Based on the description, it sounds easy to downlevel to ES5:

// The same, right?
const arr = [1].concat(arr2);
However, this is observably different in certain rare cases. For example, if an array has a “hole” in it, the missing index will create an own property if spreaded, but will not if built using concat:

// Make an array where the '1' element is missing
let missing = [0, , 1];
let spreaded = [...missing];
let concated = [].concat(missing);

// true
"1" in spreaded;
// false
"1" in concated;
Just as with for / of, downlevelIteration will use Symbol.iterator (if present) to more accurately emulate ES 6 behavior.

Default:
false
Released:
2.3
# Import Helpers - importHelpers
For certain downleveling operations, TypeScript uses some helper code for operations like extending class, spreading arrays or objects, and async operations. By default, these helpers are inserted into files which use them. This can result in code duplication if the same helper is used in many different modules.

If the importHelpers flag is on, these helper functions are instead imported from the tslib module. You will need to ensure that the tslib module is able to be imported at runtime. This only affects modules; global script files will not attempt to import modules.

For example, with this TypeScript:

export function fn(arr: number[]) {
  const arr2 = [1, ...arr];
}
Turning on downlevelIteration and importHelpers is still false:

var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spread = (this && this.__spread) || function () {
    for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
    return ar;
};
export function fn(arr) {
    var arr2 = __spread([1], arr);
}Try
Then turning on both downlevelIteration and importHelpers:

import { __read, __spread } from "tslib";
export function fn(arr) {
    var arr2 = __spread([1], arr);
}Try
You can use noEmitHelpers when you provide your own implementations of these functions.

Default:
false
Related:
noEmitHelpers, downlevelIteration, importHelpers
# Incremental - incremental
Tells TypeScript to save information about the project graph from the last compilation to files stored on disk. This creates a series of .tsbuildinfo files in the same folder as your compilation output. They are not used by your JavaScript at runtime and can be safely deleted. You can read more about the flag in the 3.4 release notes.

To control which folders you want to the files to be built to, use the config option tsBuildInfoFile.

Default:
true
Related:
composite, tsBuildInfoFile
Released:
3.4
# Isolated Modules - isolatedModules
While you can use TypeScript to produce JavaScript code from TypeScript code, it’s also common to use other transpilers such as Babel to do this. However, other transpilers only operate on a single file at a time, which means they can’t apply code transforms that depend on understanding the full type system. This restriction also applies to TypeScript’s ts.transpileModule API which is used by some build tools.

These limitations can cause runtime problems with some TypeScript features like const enums and namespaces. Setting the isolatedModules flag tells TypeScript to warn you if you write certain code that can’t be correctly interpreted by a single-file transpilation process.

It does not change the behavior of your code, or otherwise change the behavior of TypeScript’s checking and emitting process.

Some examples of code which does not work when isolatedModules is enabled.

Exports of Non-Value Identifiers
In TypeScript, you can import a type and then subsequently export it:

import { someType, someFunction } from "someModule";

someFunction();

export { someType, someFunction };Try
Because there’s no value for someType, the emitted export will not try to export it (this would be a runtime error in JavaScript):

export { someFunction };
Single-file transpilers don’t know whether someType produces a value or not, so it’s an error to export a name that only refers to a type.

Non-Module Files
If isolatedModules is set, all implementation files must be modules (which means it has some form of import/export). An error occurs if any file isn’t a module:

function fn() {}
All files must be modules when the '--isolatedModules' flag is provided.
Try
This restriction doesn’t apply to .d.ts files

References to const enum members
In TypeScript, when you reference a const enum member, the reference is replaced by its actual value in the emitted JavaScript. Changing this TypeScript:

declare const enum Numbers {
  Zero = 0,
  One = 1,
}
console.log(Numbers.Zero + Numbers.One);Try
To this JavaScript:

"use strict";
console.log(0 + 1);Try
Without knowledge of the values of these members, other transpilers can’t replace the references to Number, which would be a runtime error if left alone (since there are no Numbers object at runtime). Because of this, when isolatedModules is set, it is an error to reference an ambient const enum member.

Default:
false
# JSX - jsx
Controls how JSX constructs are emitted in JavaScript files. This only affects output of JS files that started in .tsx files.

react: Emit .js files with JSX changed to the equivalent React.createElement calls
preserve: Emit .jsx files with the JSX unchanged
react-native: Emit .js files with the JSX unchanged
Allowed:
react (default),
react-native,
preserve
Released:
2.2
# Lib - lib
TypeScript includes a default set of type definitions for built-in JS APIs (like Math), as well as type definitions for things found in browser environments (like document). TypeScript also includes APIs for newer JS features matching the target you specify; for example the definition for Map is available if target is ES6 or newer.

You may want to change these for a few reasons:

Your program doesn’t run in a browser, so you don’t want the "dom" type definitions
Your runtime platform provides certain JavaScript API objects (maybe through polyfills), but doesn’t yet support the full syntax of a given ECMAScript version
You have polyfills or native implementations for some, but not all, of a higher level ECMAScript version
High Level libraries
Name Contents
ES5 Core definitions for all ES3 and ES5 functionality
ES2015 Additional APIs available in ES2015 (also known as ES6) - array.find, Promise, Proxy, Symbol, Map, Set, Reflect, etc.
ES6 Alias for “ES2015”
ES2016 Additional APIs available in ES2016 - array.include, etc.
ES7 Alias for “ES2016”
ES2017 Additional APIs available in ES2017 - Object.entries, Object.values, Atomics, SharedArrayBuffer, date.formatToParts, typed arrays, etc.
ES2018 Additional APIs available in ES2018 - async iterables, promise.finally, Intl.PluralRules, rexexp.groups, etc.
ES2019 Additional APIs available in ES2019 - array.flat, array.flatMap, Object.fromEntries, string.trimStart, string.trimEnd, etc.
ES2020 Additional APIs available in ES2020 - string.matchAll, etc.
ESNext Additional APIs available in ESNext - This changes as the JavaScript specification evolves
DOM DOM definitions - window, document, etc.
WebWorker APIs available in WebWorker contexts
ScriptHost APIs for the Windows Script Hosting System
Individual library components
Name
DOM.Iterable
ES2015.Core
ES2015.Collection
ES2015.Generator
ES2015.Iterable
ES2015.Promise
ES2015.Proxy
ES2015.Reflect
ES2015.Symbol
ES2015.Symbol.WellKnown
ES2016.Array.Include
ES2017.object
ES2017.Intl
ES2017.SharedMemory
ES2017.String
ES2017.TypedArrays
ES2018.Intl
ES2018.Promise
ES2018.RegExp
ES2019.Array
ES2019.Full
ES2019.Object
ES2019.String
ES2019.Symbol
ES2020.Full
ES2020.String
ES2020.Symbol.wellknown
ESNext.AsyncIterable
ESNext.Array
ESNext.Intl
ESNext.Symbol
This list may be out of date, you can see the full list in the TypeScript source code.

Allowed:
See main content
Released:
2.0
# Module - module
Sets the module system for the program. See the Modules chapter of the handbook for more information. You very likely want "CommonJS".

Here’s some example output for this file:

// @filename: index.ts
import { valueOfPi } from "./constants";

export const twoPi = valueOfPi * 2;Try
CommonJS
const constants_1 = require("./constants");
exports.twoPi = constants_1.valueOfPi * 2;Try
UMD
(function (factory) {
    if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "./constants"], factory);
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    const constants_1 = require("./constants");
    exports.twoPi = constants_1.valueOfPi * 2;
});Try
AMD
define(["require", "exports", "./constants"], function (require, exports, constants_1) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.twoPi = void 0;
    exports.twoPi = constants_1.valueOfPi * 2;
});Try
System
System.register(["./constants"], function (exports_1, context_1) {
    "use strict";
    var constants_1, twoPi;
    var __moduleName = context_1 && context_1.id;
    return {
        setters: [
            function (constants_1_1) {
                constants_1 = constants_1_1;
            }
        ],
        execute: function () {
            exports_1("twoPi", twoPi = constants_1.valueOfPi * 2);
        }
    };
});Try
ESNext
import { valueOfPi } from "./constants";
export const twoPi = valueOfPi * 2;Try
ES2020
import { valueOfPi } from "./constants";
export const twoPi = valueOfPi * 2;Try
None
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.twoPi = void 0;
const constants_1 = require("./constants");
exports.twoPi = constants_1.valueOfPi * 2;Try
Allowed:
CommonJS (default if target is ES3 or ES5),
,
ES6/ES2015 (synonymous, default for target ES6 and higher),
,
ES2020,
None,
UMD,
AMD,
System,
ESNext
Released:
1.0
# No Emit - noEmit
Do not emit compiler output files like JavaScript source code, source-maps or declarations.

This makes room for another tool like Babel, or swc to handle converting the TypeScript file to a file which can run inside a JavaScript environment.

You can then use TypeScript as a tool for providing editor integration, and as a source code type-checker.

Default:
false
# Out Dir - outDir
If specified, .js (as well as .d.ts, .js.map, etc.) files will be emitted into this directory. The directory structure of the original source files is preserved; see rootDir if the computed root is not what you intended.

If not specified, .js files will be emitted in the same directory as the .ts files they were generated from:

$ tsc

example
├── index.js
└── index.ts
With a tsconfig.json like this:

{
  "compilerOptions": {
    "outDir": "dist"
  }
}
Running tsc with these settings moves the files into the specified dist folder:

$ tsc

example
├── dist
│   └── index.js
├── index.ts
└── tsconfig.json
Default:
n/a
Related:
out, outFile
# Out File - outFile
If specified, all global (non-module) files will be concatenated into the single output file specified.

If module is system or amd, all module files will also be concatenated into this file after all global content.

Note: outFile cannot be used unless module is None, System, or AMD. This option cannot be used to bundle CommonJS or ES6 modules.

Default:
n/a
Related:
out, outDir
Released:
1.0
# Plugins - plugins
List of language service plugins to run inside the editor.

Language service plugins are a way to provide additional information to a user based on existing TypeScript files. They can enhance existing messages between TypeScript and an editor, or to provide their own error messages.

For example:

ts-sql-plugin — Adds SQL linting with a template strings SQL builder.
typescript-styled-plugin — Provides CSS linting inside template strings .
typescript-eslint-language-service — Provides eslint error messaging and fix-its inside the compiler’s output.
ts-graphql-plugin — Provides validation and auto-completion inside GraphQL query template strings.
VS Code has the ability for a extension to automatically include language service plugins, and so you may have some running in your editor without needing to define them in your tsconfig.json.

# Remove Comments - removeComments
Strips all comments from TypeScript files when converting into JavaScript. Defaults to false.

For example, this is a TypeScript file which has a JSDoc comment:

/** The translation of 'Hello world' into Portuguese */
export const helloWorldPTBR = "Olá Mundo";
When removeComments is set to true:

export const helloWorldPTBR = "Olá Mundo";Try
Without setting removeComments or having it as false:

/** The translation of 'Hello world' into Portuguese */
export const helloWorldPTBR = "Olá Mundo";Try
This means that your comments will show up in the JavaScript code.

Default:
false
# Root Dir - rootDir
Default: The longest common path of all non-declaration input files. If composite is set, the default is instead the directory containing the tsconfig.json file.

When TypeScript compiles files, it keeps the same directory structure in the output directory as exists in the input directory.

For example, let’s say you have some input files:

MyProj
├── tsconfig.json
├── core
│   ├── a.ts
│   ├── b.ts
│   ├── sub
│   │   ├── c.ts
├── types.d.ts
The inferred value for rootDir is the longest common path of all non-declaration input files, which in this case is core/.

If your outDir was dist, TypeScript would write this tree:

MyProj
├── dist
│   ├── a.ts
│   ├── b.ts
│   ├── sub
│   │   ├── c.ts
However, you may have intended for core to be part of the output directory structure. By setting rootDir: "." in tsconfig.json, TypeScript would write this tree:

MyProj
├── dist
│   ├── core
│   │   ├── a.js
│   │   ├── b.js
│   │   ├── sub
│   │   │   ├── c.js
Importantly, rootDir does not affect which files become part of the compilation. It has no interaction with the include, exclude, or files tsconfig.json settings.

Note that TypeScript will never write an output file to a directory outside of outDir, and will never skip emitting a file. For this reason, rootDir also enforces that all files which need to be emitted are underneath the rootDir path.

For example, let’s say you had this tree:

MyProj
├── tsconfig.json
├── core
│   ├── a.ts
│   ├── b.ts
├── helpers.ts
It would be an error to specify rootDir as core and include as * because it creates a file (helpers.ts) that would need to be emitted outside the outDir (i.e. ../helpers.js).

Default:
Computed from the list of input files
Released:
1.5
# Source Map - sourceMap
Enables the generation of sourcemap files. These files allow debuggers and other tools to display the original TypeScript source code when actually working with the emitted JavaScript files. Source map files are emitted as .js.map (or .jsx.map) files next to the corresponding .js output file.

The .js files will in turn contain a sourcemap comment to indicate to tools where the files are to external tools, for example:

// helloWorld.ts
export declare const helloWorld = "hi";
Compiling with sourceMap set to true creates the following JavaScript file:

// helloWorld.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.helloWorld = "hi";
//# sourceMappingURL=// helloWorld.js.map
And this also generates this json map:

// helloWorld.js.map
{
  "version": 3,
  "file": "ex.js",
  "sourceRoot": "",
  "sources": ["../ex.ts"],
  "names": [],
  "mappings": ";;AAAa,QAAA,UAAU,GAAG,IAAI,CAAA"
}
Default:
false
# Target - target
Modern browsers support all ES6 features, so ES6 is a good choice. You might choose to set a lower target if your code is deployed to older environments, or a higher target if your code is guaranteed to run in newer environments.

The target setting changes which JS features are downleveled and which are left intact. For example, an arrow function () => this will be turned into an equivalent function expression if target is ES5 or lower.

Changing target also changes the default value of lib. You may “mix and match” target and lib settings as desired, but you could just set target for convenience.

If you are only working with Node.js, here are recommended targets based on the Node version:

Name Supported Target
Node 8 ES2017
Node 10 ES2018
Node 12 ES2019
These are based on node.green’s database of support.

The special ESNext value refers to the highest version your version of TypeScript supports. This setting should be used with caution, since it doesn’t mean the same thing between different TypeScript versions and can make upgrades less predictable.

Default:
es5
Allowed:
ES3 (default),
ES5,
ES6/ES2015 (synonomous),
ES7/ES2016,
ES2017,
ES2018,
ES2019,
ES2020,
ESNext
Released:
1.0
# TS Build Info File - tsBuildInfoFile
This setting lets you specify a file for storing incremental compilation information as a part of composite projects which enables faster building of larger TypeScript codebases. You can read more about composite projects in the handbook.

This option offers a way to configure the place where TypeScript keeps track of the files it stores on the disk to indicate a project’s build state — by default, they are in the same folder as your emitted JavaScript.

Default:
.tsbuildinfo
Released:
3.4

TypeScript - (tsconfig) File Inclusion

#File Inclusion
These settings help you ensure that TypeScript picks up the right files.

# Exclude - exclude
Specifies an array of filenames or patterns that should be skipped when resolving include.

Important: exclude only changes which files are included as a result of the include setting. A file specified by exclude can still become part of your codebase due to an import statement in your code, a types inclusion, a /// <reference directive, or being specified in the files list.

It is not a mechanism that prevents a file from being included in the codebase - it simply changes what the include setting finds.

Default:
["node_modules", "bower_components", "jspm_packages"], plus the value of outDir if one is specified.
Related:
include, files
# Extends - extends
The value of extends is a string which contains a path to another configuration file to inherit from. The path may use Node.js style resolution.

The configuration from the base file are loaded first, then overridden by those in the inheriting config file. All relative paths found in the configuration file will be resolved relative to the configuration file they originated in.

It’s worth noting that files, include and exclude from the inheriting config file overwrite those from the base config file, and that circularity between configuration files is not allowed.

Currently, the only top-level property that is excluded from inheritance is references.

Example
configs/base.json:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}
tsconfig.json:

{
  "extends": "./configs/base",
  "files": ["main.ts", "supplemental.ts"]
}
tsconfig.nostrictnull.json:

{
  "extends": "./tsconfig",
  "compilerOptions": {
    "strictNullChecks": false
  }
}
Properties with relative paths found in the configuration file, which aren’t excluded from inheritance, will be resolved relative to the configuration file they originated in.

Default:
false
Released:
2.1
# Files - files
Specifies an allowlist of files to include in the program. An error occurs if any of the files can’t be found.

{
  "compilerOptions": {},
  "files": [
    "core.ts",
    "sys.ts",
    "types.ts",
    "scanner.ts",
    "parser.ts",
    "utilities.ts",
    "binder.ts",
    "checker.ts",
    "tsc.ts"
  ]
}
This is useful when you only have a small number of files and don’t need to use a glob to reference many files. If you need that then use include.

Default:
false
Related:
include, exclude
# Include - include
Specifies an array of filenames or patterns to include in the program. These filenames are resolved relative to the directory containing the tsconfig.json file.

{
  "include": ["src/**/*", "tests/**/*"]
}
Which would include:

.
├── scripts                ⨯
│   ├── lint.ts            ⨯
│   ├── update_deps.ts     ⨯
│   └── utils.ts           ⨯
├── src                    ✓
│   ├── client             ✓
│   │    ├── index.ts      ✓
│   │    └── utils.ts      ✓
│   ├── server             ✓
│   │    └── index.ts      ✓
├── tests                  ✓
│   ├── app.test.ts        ✓
│   ├── utils.ts           ✓
│   └── tests.d.ts         ✓
├── package.json
├── tsconfig.json
└── yarn.lock
include and exclude support wildcard characters to make glob patterns:

* matches zero or more characters (excluding directory separators)
? matches any one character (excluding directory separators)
**/ matches any directory nested to any level
If a glob pattern doesn’t include a file extension, then only files with supported extensions are included (e.g. .ts, .tsx, and .d.ts by default, with .js and .jsx if allowJs is set to true).

Default:
false
Related:
files, exclude
Released:
2.0
# References - references
Project references are a way to structure your TypeScript programs into smaller pieces. Using Project References can greatly improve build and editor interaction times, enforce logical separation between components, and organize your code in new and improved ways.

You can read more about how references works in the Project References section of the handbook

Default:
false
# Type Acquisition - typeAcquisition
When you have a JavaScript project in your editor, TypeScript will provide types for your node_modules automatically using the DefinitelyTyped set of @types definitions. This is called automatic type acquisition, and you can customize it using the typeAcquisition object in your configuration.

If you would like to disable or customize this feature, create a jsconfig.json in the root of your project:

{
  "typeAcquisition": {
    "enable": false
  }
}
If you have a specific module which should be included (but isn’t in node_modules):

{
  "typeAcquisition": {
    "include": ["jest"]
  }
}
If a module should not be automatically acquired, for example if the library is available in your node_modules but your team has agreed to not use it:

{
  "typeAcquisition": {
    "exclude": ["jquery"]
  }
}
Default:
false

Angular Opting in to Strict Mode

Angular v10 strict opt-in mode that allows to perform more build-time optimizations and help you deliver faster apps with fewer defects. This mode is still only an opt-in because it comes with its trade-offs — stricter type checking and extra configuration.

Opting in to Strict Mode

To opt into the strict mode, you need to create a new Angular CLI app, specifying the --strict flag:

ng new my-app --strict

The command above will generate a workspace with the following settings enabled on top of the defaults:

  • Strict mode in TypeScript, as well as other strictness flags recommended by the TypeScript team. Specifically, strict, forceConsistentCasingInFileNames, noImplicitReturns, noFallthroughCasesInSwitch
  • Turns on strict Angular compiler flags strictTemplates and strictInjectionParameters
  • Reduced bundle size budgets by ~75%
  • Turns on no-any TSLint rule to prevent declarations of type any
  • Marks your application as side-effect free to enable more advanced tree-shaking


Stricter Type Checking


Researchers have proven empirically that TypeScript’s compiler helps us fix more issues before we ship our app to production. For more details, check “To Type or Not to Type: Quantifying Detectable Bugs in JavaScript.” To not step on the way of folks getting started with Angular, by default, we currently don’t enable the strictest TypeScript compiler options in new CLI workspaces.

One of the first things many developers using Angular do, to get more help from the compiler is to enable the following flags in tsconfig.json:


  • strictPropertyInitialization
  • strictNullChecks
  • noImplicitAny
  • strictBindCallApply
  • strictFunctionTypes


This way, they can more confidently ship to production because the compiler has given them some guarantees that their app aligns to a specific contract, defined by the type system. In the CLI’s strict mode, we enable the TypeScript’s strict flag, which turns these on by default.

Two of the flags that will have the biggest impact on your development process are strictPropertyInitialization and strictNullChecks. With strictPropertyInitialization, the following snippet will throw a compile-time error because we haven’t initialized title:

@Component({...})
class AppComponent {
  @Input() title: string;
}

To fix it, you’d have to either set title to a string value or change its type, for instance:

@Component({...})
class AppComponent {
  @Input() title = '';
}

One additional check we’ve enabled is the no-any TSLint rule (yes, we’ll be moving away from TSLint; this rule has its ESLint equivalent). This way, we can use more type information during our ng update command and more confidently migrate your apps across Angular versions. Let us look at an example:

import { HttpClient } from '@angular/common/http';

@Component({...})
export class AppComponent {
  client: any;
  constructor(http: HttpClient) {
    this.client = http;
  }

  handleClick() {
    this.client.deprecatedMethod();
  }
}

If we wanted to migrate your project away from deprecatedMethod we wouldn’t have been able to given that the type of client is any. To migrate your project with confidence, we’d need the information that client has the type of HttpClient with an explicit type annotation: client: HttpClient. This way we’d know that deprecatedMethod belongs to our migration target rather than it just happened that another object has a method with the same name.

The strictTemplates flag is an Angular specific configuration that strict mode enables under angularCompilerOptions in tsconfig.json. Let’s look at the following snippet:

<div *ngFor="let todo of todos">
  <h2>{{ todo.title }}</h2>
  <button *ngIf="user.isAdmin">Edit</button>
</div>

Currently, Angular will not perform any type checking at compile-time. If you enable strictTemplates, Angular will check if todo has a property title and if user.isAdmin exists. Additionally, if you have any of the strict TypeScript flags enabled, the Angular compiler will enable the same strictness checks for the template. For example, if we have strictNullChecks and strictTemplates in the following snippet we’ll get a type error:

@Component({
  template: '<h1>{{ article.title }}</h1>'
})
class ArticleComponent {
  article: Article | undefined;
}

This will help us ensure we’ve initialized article before accessing its property. A way to fix this error would be: <h1>{{ article?.title }}</h1> using the safe navigation operator (similar to optional chaining).

Trade-offs

[Con] The compiler will be stricter. It will throw compile-time errors if you haven’t initialized a property, check if an expression is null, if you have type errors in your templates, etc. If you want to prototype something rapidly and correctness is not important to you, this may slow you down. Such compile-time errors could also be confusing for people getting started with Angular.

[Pro] strictNullChecks and strictPropertyInitialization will make sure you’re not accessing properties or calling methods of null references.

[Pro] Angular will also be able to help you discover more issues ahead of time by type checking your templates.


Tighter Bundle Budgets


Bundle budgets provide a guarantee that the performance of your app will not unnoticeably regress over time. In Angular CLI’s angular.json file, we have predefined error and warning budgets. If the size of a specific JavaScript bundle or style exceeds the warning budget, you’ll get a warning message; if you exceed the error budget, your build will fail.

By default, we’ve set pretty high budgets:

  • 2MB warning and 5MB error budget for the initial JavaScript we send to the browser
  • 6KB warning and 10KB error budget for the styles of any component


In strict mode, these numbers drop to:

  • 500KB warning and 1MB error budget for the initial JavaScript we send to the browser
  • 2KB warning and 4KB error budget for the styles of any component


To make sure you fit the budget:

  • Make sure you are aware of what you have in your production bundles. source-map-explorer will come handy here
  • Use lazy-loading
  • Avoid large imports in your component styles


Trade-offs

[Con] According to reports we have, over 50% of apps ship more than 1MB of JavaScript. With the tighter bundle budgets, your build will fail if you exceed this number. If the initial load time performance of your app is not critical for your use case, you’ll be getting build failures and you will have to update the budget manually.

[Pro] If you introduce a large dependency by accident, your build will fail, and you’ll catch the regression ahead of time. Overall, bundle budgets will guard your application against growing in size.

Reduced side effects

The last strict mode option we will look at is related to tree-shaking. Tree-shaking is a form of dead code elimination, in which the build tooling removes unused code. To enable webpack to remove unused modules, in the strict mode, we create an extra package.json with all of your apps and libraries. This package.json file has a single property - sideEffects set to false.

It’s practically impossible to determine with static code analysis if a module produces side effects or not in a language as dynamic as JavaScript. This means that our optimistic assumption may potentially break your app. Let us look into more details what this actually means.

Currently, with the Angular CLI webpack delegates tree-shaking to terser, the JavaScript optimizer we use. Let’s look at an example:


// constants.js
export const PI = 3.14159265357989;

// index.js
import { add } from './utils';
const subtract = (a, b) => a - b;

console.log(add(1, 2));

// operations.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

// utils.js
export * from './operations';
export * from './constants';

Here we have the following dependency graph:



When we run webpack with entry point index.js we’ll get the following output:

/******/ (() => { // webpackBootstrap
/******/ "use strict";

// CONCATENATED MODULE: ./operations.js
// utils.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

// CONCATENATED MODULE: ./constants.js
const PI = 3.14159265357989;

// CONCATENATED MODULE: ./utils.js

// CONCATENATED MODULE: ./index.js
// index.js
const index_subtract = (a, b) => a - b;
console.log(add(1, 2));
/******/ })();

Notice that although we don’t use subtract and PI, they are still in the final bundle. If we run webpack in production mode, terser will statistically determine that we’re only using add, and it will get rid of the exported subtract and PI.

webpack includes the module constants.js in the final bundle only because it’s not sure if it produces side effects or not. For example, if it adds globals, writes to localStorage, or sends HTTP requests, removing this module will break our app.

Suppose we specify the sideEffects property to false in the corresponding package.json to our project. In that case, webpack will assume utils.js, constants.js, and operations.js do not produce any side effects and will not include the unused modules in the final bundle. Here’s what the final bundle would look like in this case:

/******/ (() => { // webpackBootstrap
/******/ "use strict";

// CONCATENATED MODULE: ./utils.js
// utils.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

// CONCATENATED MODULE: ./index.js
// index.js

const index_subtract = (a, b) => a - b;
console.log(add(1, 2));

/******/ })();

If we enable terser, it’ll get rid of index_subtract and subtract since we don’t use them, and inline add, which will produce:

(()=>{"use strict";console.log(1+2)})();


Trade-offs

[Con] You now have multiple package.json files — one for your workspace, and one for each of your libraries and apps. This could be confusing for folks getting started with Angular CLI.

[Con] If you have side effects in any of your modules and webpack tree-shakes it away, you’ll get a runtime error.

[Pro] You’ll get smaller apps overall.

Let us spend a minute to look at the second point. Imagine constants.js had the following content:

// constants.js
export const PI = 3.14159265357989;
localStorage.setItem('foo', 'bar');

If we have incorrectly specified the sideEffects flag to false and webpack gets rid of this module since we don’t reference it, the localStorage.setItem('foo', 'bar') statement will not execute. This, later on, can lead to issues in our app if we rely that we have this information in localStorage.

Everything we mentioned so far has its trade-offs. If we want fewer issues in production, we need to fight with stricter compiler options, and if we want smaller bundles, we may have to enable extra, potentially unsafe configuration.

2020-08-27

Hibernate JPA @WhereJoinTable Example

@WhereJoinTable

The @WhereJoinTable annotation is used to specify a custom SQL WHERE clause used when fetching a join collection table.

WhereJoinTable Where clause to add to the collection join table. The clause is written in SQL. Just as with Where, a common use case is for implementing soft-deletes.

@WhereJoinTable
Just like @Where annotation, @WhereJoinTable is used to filter out collections using a joined table (e.g. @ManyToMany association).

Example : @WhereJoinTable mapping example

@Entity(name = "Book")
public static class Book {

@Id
private Long id;

private String title;

private String author;

@ManyToMany
@JoinTable(
name = "Book_Reader",
joinColumns = @JoinColumn(name = "book_id"),
inverseJoinColumns = @JoinColumn(name = "reader_id")
)
@WhereJoinTable( clause = "created_on > DATEADD( 'DAY', -7, CURRENT_TIMESTAMP() )")
private List<Reader> currentWeekReaders = new ArrayList<>( );

//Getters and setters omitted for brevity

}

@Entity(name = "Reader")
public static class Reader {

@Id
private Long id;

private String name;

//Getters and setters omitted for brevity

}

Hibernate JPA @Where Example

@Where

The @Where annotation is used to specify a custom SQL WHERE clause used when fetching an entity or a collection.

Where clause to add to the element Entity or target entity of a collection. The clause is written in SQL. A common use case here is for soft-deletes.

@Where mapping usage

public enum AccountType {
DEBIT,
CREDIT
}

@Entity(name = "Client")
public static class Client {

@Id
private Long id;

private String name;

@Where( clause = "account_type = 'DEBIT'")
@OneToMany(mappedBy = "client")
private List<Account> debitAccounts = new ArrayList<>( );

@Where( clause = "account_type = 'CREDIT'")
@OneToMany(mappedBy = "client")
private List<Account> creditAccounts = new ArrayList<>( );

//Getters and setters omitted for brevity

}

@Entity(name = "Account")
@Where( clause = "active = true" )
public static class Account {

@Id
private Long id;

@ManyToOne
private Client client;

@Column(name = "account_type")
@Enumerated(EnumType.STRING)
private AccountType type;

private Double amount;

private Double rate;

private boolean active;

//Getters and setters omitted for brevity

}

Hibernate JPA @ValueGenerationType Example

@ValueGenerationType

The @ValueGenerationType annotation is used to specify that the current annotation type should be used as a generator annotation type.

ValueGenerationType marks an annotation type as a generator annotation type.
Adding a generator annotation to an entity property causes the value of the property to be generated upon insert or update of the owning entity. Not more than one generator annotation may be placed on a given property.

Each generator annotation type is associated with a AnnotationValueGeneration which implements the strategy for generating the value. Generator annotation types may define arbitrary custom attributes, e.g. allowing the client to configure the generation timing (if applicable) or other settings taking an effect on the value generation. The corresponding implementation can retrieve these settings from the annotation instance passed to AnnotationValueGeneration.initialize(java.lang.annotation.Annotation, Class).

Custom generator annotation types must have retention policy RetentionPolicy.RUNTIME.

A ValueGenerationType mapping for database generation

@Entity(name = "Event")
public static class Event {

@Id
@GeneratedValue
private Long id;

@Column(name = "`timestamp`")
@FunctionCreationTimestamp
private Date timestamp;

//Constructors, getters, and setters are omitted for brevity
}

@ValueGenerationType(generatedBy = FunctionCreationValueGeneration.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionCreationTimestamp {}

public static class FunctionCreationValueGeneration
implements AnnotationValueGeneration<FunctionCreationTimestamp> {

@Override
public void initialize(FunctionCreationTimestamp annotation, Class<?> propertyType) {
}

/**
* Generate value on INSERT
* @return when to generate the value
*/
public GenerationTiming getGenerationTiming() {
return GenerationTiming.INSERT;
}

/**
* Returns null because the value is generated by the database.
* @return null
*/
public ValueGenerator<?> getValueGenerator() {
return null;
}

/**
* Returns true because the value is generated by the database.
* @return true
*/
public boolean referenceColumnInSql() {
return true;
}

/**
* Returns the database-generated value
* @return database-generated value
*/
public String getDatabaseGeneratedReferencedColumnValue() {
return "current_timestamp";
}
}
When persisting an Event entity, Hibernate generates the following SQL statement:

INSERT INTO Event ("timestamp", id)
VALUES (current_timestamp, 1)
As you can see, the current_timestamp value was used for assigning the timestamp column value.

In-memory-generated values
If the timestamp value needs to be generated in-memory, the following mapping must be used instead:

Example : A ValueGenerationType mapping for in-memory value generation

@Entity(name = "Event")
public static class Event {

@Id
@GeneratedValue
private Long id;

@Column(name = "`timestamp`")
@FunctionCreationTimestamp
private Date timestamp;

//Constructors, getters, and setters are omitted for brevity
}

@ValueGenerationType(generatedBy = FunctionCreationValueGeneration.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionCreationTimestamp {}

public static class FunctionCreationValueGeneration
implements AnnotationValueGeneration<FunctionCreationTimestamp> {

@Override
public void initialize(FunctionCreationTimestamp annotation, Class<?> propertyType) {
}

/**
* Generate value on INSERT
* @return when to generate the value
*/
public GenerationTiming getGenerationTiming() {
return GenerationTiming.INSERT;
}

/**
* Returns the in-memory generated value
* @return {@code true}
*/
public ValueGenerator<?> getValueGenerator() {
return (session, owner) -> new Date( );
}

/**
* Returns false because the value is generated by the database.
* @return false
*/
public boolean referenceColumnInSql() {
return false;
}

/**
* Returns null because the value is generated in-memory.
* @return null
*/
public String getDatabaseGeneratedReferencedColumnValue() {
return null;
}
}
When persisting an Event entity, Hibernate generates the following SQL statement:

INSERT INTO Event ("timestamp", id)
VALUES ('Tue Mar 01 10:58:18 EET 2016', 1)
As you can see, the new Date() object value was used for assigning the timestamp column value.

Hibernate JPA @UpdateTimestamp Example

@UpdateTimestamp

The @UpdateTimestamp annotation is used to specify that the currently annotated timestamp attribute should be updated with the current JVM timestamp whenever the owning entity gets modified.

java.util.Date

java.util.Calendar

java.sql.Date

java.sql.Time

java.sql.Timestamp


UpdateTimestamp marks a property as the update timestamp of the containing entity. The property value will be set to the current VM date whenever the owning entity is updated.
Supported property types:


  • Date
  • Calendar
  • Date
  • Time
  • Timestamp
  • Instant
  • LocalDate
  • LocalDateTime
  • LocalTime
  • MonthDay
  • OffsetDateTime
  • OffsetTime
  • Year
  • YearMonth
  • ZonedDateTime


@UpdateTimestamp annotation
The @UpdateTimestamp annotation instructs Hibernate to set the annotated entity attribute with the current timestamp value of the JVM when the entity is being persisted.

The supported property types are:


  • java.util.Date

  • java.util.Calendar

  • java.sql.Date

  • java.sql.Time

  • java.sql.Timestamp


Example : @UpdateTimestamp mapping example

@Entity(name = "Bid")
public static class Bid {

@Id
@GeneratedValue
private Long id;

@Column(name = "updated_on")
@UpdateTimestamp
private Date updatedOn;

@Column(name = "updated_by")
private String updatedBy;

private Long cents;

//Getters and setters are omitted for brevity

}

Hibernate JPA @TypeDef Example

@TypeDef

The @TypeDef annotation is used to specify a @Type definition which can later be reused for multiple basic attribute mappings.

TypeDef is a type definition. Much like Type, but here we can centralize the definition under a name and refer to that name elsewhere. The plural form is TypeDefs.

@TypeDef to register a custom Type

@Entity(name = "Product")
@TypeDef(
name = "bitset",
defaultForType = BitSet.class,
typeClass = BitSetType.class
)
public static class Product {

@Id
private Integer id;

private BitSet bitSet;

//Getters and setters are omitted for brevity
}

@TypeDefs
The @TypeDefs annotation is used to group multiple @TypeDef annotations.

Hibernate JPA @Type Example

@Type

The @Type annotation is used to specify the Hibernate @Type used by the currently annotated basic attribute.

Custom BasicType mapping

@Entity(name = "Product")
public static class Product {

@Id
private Integer id;

@Type( type = "bitset" )
private BitSet bitSet;

public Integer getId() {
return id;
}

//Getters and setters are omitted for brevity
}