Type Checking
allowUnreachableCode
- Released: 1.8
When:
undefined(default) provide suggestions as warnings to editorstrueunreachable code is ignoredfalseraises compiler errors about unreachable code
These warnings are only about code which is provably unreachable due to the use of JavaScript syntax, for example:
function fn(n: number) {
if (n > 5) {
return true;
} else {
return false;
}
return true;
}With "allowUnreachableCode": false:
function fn(n: number) {
if (n > 5) {
return true;
} else {
return false;
}
return true;Unreachable code detected.}TryThis does not affect errors on the basis of code which appears to be unreachable due to type analysis.
allowUnusedLabels
- Released: 1.8
When:
undefined(default) provide suggestions as warnings to editorstrueunused labels are ignoredfalseraises compiler errors about unused labels
Labels are very rare in JavaScript and typically indicate an attempt to write an object literal:
function verifyAge(age: number) {
// Forgot 'return' statement
if (age > 18) {
verified: true;Unused label. }
}TryalwaysStrict
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.
exactOptionalPropertyTypes Recommended
- Released: 4.4
With exactOptionalPropertyTypes enabled, TypeScript applies stricter rules around how it handles properties on type or interfaces which have a ? prefix.
For example, this interface declares that there is a property which can be one of two strings: 'dark' or 'light' or it should not be in the object.
interface UserDefaults {
// The absence of a value represents 'system'
colorThemeOverride?: "dark" | "light";
}Without this flag enabled, there are three values which you can set colorThemeOverride to be: "dark", "light" and undefined.
Setting the value to undefined will allow most JavaScript runtime checks for the existence to fail, which is effectively falsy. However, this isn't quite accurate; colorThemeOverride: undefined is not the same as colorThemeOverride not being defined. For example, "colorThemeOverride" in settings would have different behavior with undefined as the key compared to not being defined.
exactOptionalPropertyTypes makes TypeScript truly enforce the definition provided as an optional property:
const settings = getUserSettings();
settings.colorThemeOverride = "dark";
settings.colorThemeOverride = "light";
// But not:
settings.colorThemeOverride = undefined;Type 'undefined' is not assignable to type '"dark" | "light"' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.TrynoFallthroughCasesInSwitch
- Released: 1.8
Report errors for fallthrough cases in switch statements. Ensures that any non-empty case inside a switch statement includes either break, return, or throw. 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;
}TrynoImplicitAny Recommended
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:
Turning on noImplicitAny however TypeScript will issue an error whenever it would have inferred any:
noImplicitOverride
- Released: 4.3
When working with classes which use inheritance, it's possible for a sub-class to get "out of sync" with the functions it overloads when they are renamed in the base class.
For example, imagine you are modeling a music album syncing system:
class Album {
download() {
// Default behavior
}
}
class SharedAlbum extends Album {
download() {
// Override to get info from many sources
}
}TryThen when you add support for machine-learning generated playlists, you refactor the Album class to have a 'setup' function instead:
class Album {
setup() {
// Default behavior
}
}
class MLAlbum extends Album {
setup() {
// Override to get info from algorithm
}
}
class SharedAlbum extends Album {
download() {
// Override to get info from many sources
}
}TryIn this case, TypeScript has provided no warning that download on SharedAlbum expected to override a function in the base class.
Using noImplicitOverride you can ensure that the sub-classes never go out of sync, by ensuring that functions which override include the keyword override.
The following example has noImplicitOverride enabled, and you can see the error received when override is missing:
class Album {
setup() {}
}
class MLAlbum extends Album {
override setup() {}
}
class SharedAlbum extends Album {
setup() {}This member must have an 'override' modifier because it overrides a member in the base class 'Album'.}TrynoImplicitReturns
- Released: 1.8
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";
}
}TrynoImplicitThis Recommended
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. };
}
}TrynoPropertyAccessFromIndexSignature
- Released: 4.2
This setting ensures consistency between accessing a field via the "dot" (obj.key) syntax, and "indexed" (obj["key"]) and the way which the property is declared in the type.
Without this flag, TypeScript will allow you to use the dot syntax to access fields which are not defined:
interface GameSettings {
// Known up-front properties
speed: "fast" | "medium" | "slow";
quality: "high" | "low";
// Assume anything unknown to the interface
// is a string.
[key: string]: string;
}
const settings = getSettings();
settings.speed;
settings.quality;
// Unknown key accessors are allowed on
// this object, and are `string`
settings.username;
TryTurning the flag on will raise an error because the unknown field uses dot syntax instead of indexed syntax.
const settings = getSettings();
settings.speed;
settings.quality;
// This would need to be settings["username"];
settings.username;Property 'username' comes from an index signature, so it must be accessed with ['username'].TryThe goal of this flag is to signal intent in your calling syntax about how certain you are this property exists.
noUncheckedIndexedAccess
- Released: 4.1
TypeScript has a way to describe objects which have unknown keys but known values on an object, via index signatures.
interface EnvironmentVars {
NAME: string;
OS: string;
// Unknown properties are covered by this index signature.
[propName: string]: string;
}
declare const env: EnvironmentVars;
// Declared as existing
const sysName = env.NAME;
const os = env.OS;
// Not declared, but because of the index
// signature, then it is considered a string
const nodeEnv = env.NODE_ENV;
TryTurning on noUncheckedIndexedAccess will add undefined to any un-declared field in the type.
declare const env: EnvironmentVars;
// Declared as existing
const sysName = env.NAME;
const os = env.OS;
// Not declared, but because of the index
// signature, then it is considered a string
const nodeEnv = env.NODE_ENV;
TrynoUnusedLocals
- Released: 2.0
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 };
};TrynoUnusedParameters
- Released: 2.0
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 };
};TryParameters declaration with names starting with an underscore (_) are exempt from the unused parameter checking. e.g.:
strict Recommended
Default:
trueReleased: 2.3
Related: alwaysStrict,strictNullChecks,strictBindCallApply,strictBuiltinIteratorReturn,strictFunctionTypes,strictPropertyInitialization,noImplicitAny,noImplicitThis,useUnknownInCatchVariables
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.
strictBindCallApply Recommended
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'.TryOtherwise, 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);TrystrictBuiltinIteratorReturn Recommended
Built-in iterators are instantiated with a TReturn type of undefined instead of any.
strictFunctionTypes Recommended
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);TryWith 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'.TryDuring 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);TrystrictNullChecks Recommended
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);TrySetting 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);'loggedInUser' is possibly 'undefined'.TryThe 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;
};strictPropertyInitialization Recommended
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
}
}TryIn the above case:
this.nameis set specifically.this.accountTypeis set by default.this.emailis not set and raises an error.this.addressis declared as potentiallyundefinedwhich means it does not have to be set.
useUnknownInCatchVariables Recommended
In TypeScript 4.0, support was added to allow changing the type of the variable in a catch clause from any to unknown. Allowing for code like:
try {
// ...
} catch (err: unknown) {
// We have to verify err is an
// error before using it as one.
if (err instanceof Error) {
console.log(err.message);
}
}TryThis pattern ensures that error handling code becomes more comprehensive because you cannot guarantee that the object being thrown is a Error subclass ahead of time. With the flag useUnknownInCatchVariables enabled, then you do not need the additional syntax (: unknown) nor a linter rule to try enforce this behavior.