Learn TypeScript
Controlling type checking strictness
Controlling type checking strictness
In this lesson, we will learn about all the compiler options that control the type checking's strictness.
Technical requirements
You will need the following installed on your computer for this lesson:
Node.js and npm. You can download these from https://nodejs.org/en/download. If you already have these installed, make sure that Node.js is at least version 8.2, and that npm is at least version 5.
Code editor such as Visual Studio Code. This can be installed from https://code.visualstudio.com.
The starter project which can be found here.
After the starter project has been downloaded. Open it in Visual Studio Code and execute the following command in a Terminal window:
npm installThis will install the project dependency, which is TypeScript.
Understanding TypeScript strict mode
The starter project has a compiler option switch on called strict. This turns on a set of type checking rules and is referred to as strict mode. This is separate from JavaScript's strict mode.
When creating a new TypeScript project, it is recommended to have strict mode on so that code benefits from the most stringent type checking from the start of its life. However, strict mode may not be feasible when migrating a JavaScript codebase to TypeScript because of the number of type errors raised.
In addition to the strict option, each type checking rule can be controlled via a specific compiler option. This gives fine-grain control on the type checker's strictness.
- Run the TypeScript compiler:
npm run tscSeveral type errors are raised in index.ts. In the following sections, we will learn about the strictness compiler options and its impact on index.ts.
Understanding noImplicitAny
The noImplicitAny compiler option will raise errors in expressions and declarations with an implied any type. This option is currently on because the strict option is true.
The greet method is currently violating this rule because the prefix parameter is inferred to have the any type:
public greet(prefix) { ...}- Set
noImplicitAnytofalse:
{ "compilerOptions": { ... "noImplicitAny": false }, ....}The type error on this method is resolved.
How could we change the greet function to no longer violate the noImplicitAny rule? Make this change.
- Remove the
noImplicitAnyfield intsconfig.jsonso that it is set back totrue:
There is still no type error on this method.
Neat!
Understanding noImplicitThis
The noImplicitThis compiler option raises an error on expressions that reference this with an implied any type. This option is currently on because the strict option is true.
The goodbyeFunction method is voilating this rule at the moment where the name property within this is accessed:
public goodbyeFunction() { return function () { console.log(`Goodbye ${this.name}`); };}TypeScript infers this to be of type any and so raises a type error.
- Set
noImplicitThistofalse:
{ "compilerOptions": { ... "noImplicitThis": false }, ....}The type error is resolved.
There are two ways to resolve this error properly.
The first method of resolving the type error is to let TypeScript know the type of this in the function signature:
public goodbyeFunction() { return function (this: Person) { ... };}The second method of resolving the type error is to use an arrow function:
public goodbyeFunction() { return () => { ... };}- Use one of these approaches and remove the
noImplicitThisfield intsconfig.jsonso that it is set back totrue:
There is still no type error on this code.
Nice!
Understanding strictBindCallApply
The strictBindCallApply compiler option enables stricter checking of the bind, call, and apply methods. This option is currently on because the strict option is true.
The call to person.calculatePrice in the create function is voilating this rule at the moment because calculatePrice requires two arguments to be passed in:
const discountedPrice = person.calculatePrice.apply(undefined, ["FREE"]);- Set
strictBindCallApplytofalse:
{ "compilerOptions": { ... "strictBindCallApply": false }, ....}The type error on this code is resolved.
Properly resolve the type error by passing in a second parameter for the price.
- Remove the
strictBindCallApplyfield intsconfig.jsonso that it is set back totrue:
There is still no type error on this code.
Nice!
Understanding strictNullChecks
The strictNullChecks compiler option excludes the null and undefined values in the domain of every type. This option is currently on because the strict option is true.
The assignment of person to null at the end of the create function is violating this rule at the moment because null is not within the Person type.
person = null;- Set
strictNullCheckstofalse:
{ "compilerOptions": { ... "strictNullChecks": false }, ....}The type error on this line is resolved.
How would we properly resolve the type error if we wanted to assign person to null. Make this change
- Remove the
strictNullChecksfield intsconfig.jsonso that it is set back totrue:
There is still no type error on this line.
Understanding strictFunctionTypes
The strictFunctionTypes disables bivariant parameter checking for function types. This option is currently on because the strict option is true.
The getDiscountCode function contains a type error because the info parameter contains a token property that is not part of APIRequestHandler:
const getDiscountCode: APIRequestHandler<string> = async ( info: APIRequestInfo & { token: string }) => { ... }- Set
strictFunctionTypestofalse:
{ "compilerOptions": { ... "strictFunctionTypes": false }, ....}The type error on this function is resolved.
Resolving this type error isn't straight forward. The getDiscountCode clearly requires the token property. We could change the APIRequestHandler type, but that might impact other code. A solution is to remove the type annotation from getDiscountCode and let TypeScript infer its type.
Remove the type annotation from
getDiscountCodeto resolve this error.Remove the
strictFunctionTypesfield intsconfig.jsonso that it is set back totrue:
There is still no type error on this function.
Understanding strictPropertyInitialization
The strictPropertyInitialization compiler option ensures non-undefined class properties are initialized in the constructor. This option requires strictNullChecks to be enabled to take effect. This option is currently on because the strict option is true.
The name property within the Person type is currently violating this rule.
public name: string;- Set
strictPropertyInitializationtofalse:
{ "compilerOptions": { ... "strictPropertyInitialization": false }, ....}The type error on this property is resolved.
How would we properly resolve this type error?
- Remove the
strictPropertyInitializationfield intsconfig.jsonso that it is set back totrue:
There is still no type error on this property.
Understanding alwaysStrict
The alwaysStrict compiler option ensures JavaScript strict mode is used type checking process. It also determines whether "use strict" is emitted in JavaScript. This option is currently on because the strict option is true.
- Open
index.jsin thedistfolder to verify that it includes"use strict"at the top.
"use strict";class Person ...- This is impacting a variable called
argumentsin thecreatefunction:
let arguments;Variables can't have the name "arguments" in JavaScript strict mode.
- Set
alwaysStricttofalse:
{ "compilerOptions": { ... "alwaysStrict": false }, ....}The TypeScript compiler needs to be stopped and restarted for this option to take full effect.
- Stop and restart the TypeScript compiler.
The type error is resolved.
Is 'use strict' at the top of the transpiled JavaScript file?
Rename the
argumentsvariable toargs.Remove the
alwaysStrictfield intsconfig.jsonso that it is set back totrue:Stop and restart the TypeScript compiler.
There is still no type error on this line of code.
Summary
TypeScript has a range of options for controlling how strict the type checking is:
strict- Sets maximum strictness, setting all the flags below totrue.noImplicitAny- Raises an error on expressions and declarations with an inferred type ofany.noImplicitThis- Raises an error onthisexpressions with an inferred type ofany.strictBindCallApply- Enables strict checking of thebind,call, andapplymethods on functions.strictNullChecks- Means thatnullandundefinedvalues are not valid values in types.strictFunctionTypes- Disables bivariant parameter checking for function types.strictPropertyInitialization- Ensures class properties are assigned a default value or initialized in the constructor.alwaysStrict- Parses the code in JavaScript strict mode and emits "use strict" in the transpiled code.
For new projects, it is recommended to set strict to true.
For JavaScript migration projects, strict can be set to true with the other flags to false if the corresponding rule raises lots of type errors. A goal could be to resolve the type errors and set all the strict flags to true over time.
In the next lesson, we will learn about some compile options that help with code quality.