Angular/TypeScript/JavaScript ‘Strict’ Cheatsheet

angular

Update: Jan 10 formatting, and added section ‘Leveraging Strict Mode for Enhanced Compilation and Performance’. Added Contents section.

Update: Feb 8, added section The Bottom Line.

Just the good stuff

For those who want the nugget of how to enable ‘strict’ across the 3 languages/frameworks go here: The Bottom Line.

Contents

JavaScript Strict Mode
 
· JavaScript Strict Errors Detected

TypeScript Strict Mode
 
· TSConfig.json
· TypeScript: The Thing About ‘any’

Angular Strict Mode

TypeScript ‘@types’

Strict Mode for Enhanced Compilation and Performance
 
· Benefits in Specific Environments


When I collaborated with a new team on an Angular development project, I sought to learn the best practices for ensuring type safety. With a background in .Net and C#, I understood the critical role type safety plays in delivering stable, high-quality code. This article provides the guidance I wish I had at the time.
 
 Type safety in software development guarantees that data types are used consistently with their intended purpose, preventing errors and unforeseen behavior. By detecting type-related errors at compile time or runtime, type safety minimizes the occurrence of bugs and enhances overall code reliability.
 
 When developing with Angular, you also work with TypeScript and JavaScript. Fortunately, all three technologies provide features that enable strict data typing, helping to enforce type consistency, reduce errors and improve performance.


JavaScript Strict Mode

In JavaScript, you can enable strict mode, which helps catch common coding mistakes and “unsafe” actions, by including the “use strict”; directive at the beginning of a script or a function.

Using strict mode helps improve the overall quality of your code by catching errors early, preventing the use of certain features, and generally making JavaScript behave in a more predictable way. Some of the benefits include:

  • Eliminating some silent errors by changing them to throw errors.
  • Fixing mistakes that make it difficult for JavaScript engines to perform optimizations.
  • Prohibiting some syntax likely to be defined in future versions of ECMAScript.

Enabling Strict Mode in a Script
Add “use strict”; at the top of your JavaScript file:

"use strict";
// Your code here

Enabling Strict Mode in a Function
If you want to enable strict mode only within a specific function, add “use strict”; at the beginning of the function body:

function myFunction() {
"use strict";
// Your code here
}

JavaScript Strict Errors Detected

By enabling strict mode, the following errors are detected and will cause your code to throw exceptions:

1. Assigning to Undeclared Variables: Strict mode requires that all variables be declared before they are assigned a value.

"use strict";
x = 3.1415; // ReferenceError: x is not defined

2. Assigning to Read-Only Properties: Strict mode prevents assignments to properties that are read-only.

"use strict";
const obj = {};
Object.defineProperty(obj, "x", { value: 42, writable: false });
obj.x = 99; // TypeError: Cannot assign to read-only property 'x'

3. Assigning to Non-Extensible Objects: In strict mode, you cannot add new properties to objects that are non-extensible.

"use strict";
const obj = Object.preventExtensions({});
obj.newProp = "test"; // TypeError: Cannot add property newProp, object is not extensible

4. Deleting Non-Configurable Properties: Strict mode disallows the deletion of properties that are non-configurable.

"use strict";
delete Object.prototype; // TypeError: Cannot delete property 'prototype' of function Object() { [native code] }

5. Duplicate Property Names in Objects: Strict mode throws an error if an object literal has multiple properties with the same name.

"use strict";
const obj = {
prop: 1,
prop: 2 // SyntaxError: Duplicate data property in object literal not allowed in strict mode
};

6. Duplicate Parameter Names: Strict mode disallows duplicate parameter names in function definitions.

"use strict";
function sum(a, a, c) { // SyntaxError: Duplicate parameter name not allowed in this context
return a + a + c;
}

7. Octal Syntax: Strict mode does not allow octal syntax (numbers starting with a zero).

"use strict";
const num = 0123; // SyntaxError: Octal literals are not allowed in strict mode.

8. Setting this to undefined or null: In strict mode, the value of this remains undefined or null in a function called with a non-object context.

"use strict";
function showThis() {
console.log(this); // undefined
}
showThis();

9. Implied Global Variables: Strict mode prevents the creation of global variables from within a function or block scope.

"use strict";
function doSomething() {
globalVar = "This will throw an error";

10. Setting eval or arguments as Identifiers: In strict mode, you cannot use eval or arguments as the name of variables, functions, or parameters.

"use strict";
var eval = 17; // SyntaxError: Unexpected eval or arguments in strict mode

11. Restricted eval Usage: The eval function in strict mode does not introduce new variables into the surrounding scope.

"use strict";
eval("var x = 2;");
console.log(x); // ReferenceError: x is not defined

12. Prohibited with Statement: Strict mode disallows the use of the with statement, which can make code more difficult to understand and debug.

"use strict";
with (Math) { // SyntaxError: Strict mode code may not include a with statement
x = cos(2);
}

13. Function Parameter Restrictions: In strict mode, you cannot delete function parameters.

"use strict";
function foo(a) {
delete a; // SyntaxError: Deleting local variable in strict mode
}

14. Octal Escapes: Strict mode disallows octal escape sequences in string literals.

"use strict";
var str = "\010"; // SyntaxError: Octal escape sequences are not allowed in strict mode

15. Secured this in Functions: Strict mode ensures that the this value is not coerced into the global object. If this is not explicitly set, it remains undefined.

"use strict";
function strictFunction() {
console.log(this); // undefined, not the global object
}
strictFunction();

16. Reserved Words: ECMA 5 chose to define the following as reserved for future versions.

implements
 interface
 let
 package
 private
 protected
 public
 static
 yield


TypeScript Strict Mode

TypeScript offers a set of compiler options that enable strict type-checking to help catch common errors and improve code quality. The main flag to enable strict mode is strict, which encompasses several specific strictness checks.

You can enable strict mode by adding “strict”: true to your tsconfig.json file, or by using the — strict flag when running the TypeScript compiler.

Here’s an overview of the strict flag and its components:

  1. strict: This is the main flag that enables all strict type-checking options. When set to true, it turns on all of the following specific strict flags:
  2. noImplicitAny: When this flag is enabled, the compiler will raise an error whenever it encounters a variable that has an implicit any type.
  3. strictNullChecks: This flag ensures that null and undefined are handled explicitly in your code. It prevents assigning null or undefined to variables unless their types explicitly allow it.
  4. strictFunctionTypes: This flag checks function type compatibility more strictly, ensuring that function parameters and return types are properly validated.
  5. strictBindCallApply: This flag ensures stricter checking of the bind, call, and apply methods on functions.
  6. strictPropertyInitialization: This flag ensures that class properties are properly initialized in the constructor or through property declarations.
  7. noImplicitThis: This flag ensures that this within functions is properly typed.
  8. alwaysStrict: This flag ensures that the compiler always emits “use strict”; directive in every generated JavaScript file.
  9. noUnusedLocals: This flags help catch and eliminate unused local variables.
  10. noUnusedParameters: This flags help catch and eliminate unused function parameters.

TSConfig.json

By enabling these strict type-checking options, you can write safer and more robust TypeScript code. Here’s an example tsconfig.json with all these strict options enabled:

{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,

"allowUnreachableCode": false,
"allowUnusedLabels": false,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"strictBuiltinIteratorReturn": true,
"strictFunctionTypes": true,
"useUnknownInCatchVariables": true
}
}

12. allowUnusedLabels: When true, this flag allows unused labels in your code. Labels are identifiers followed by a colon used to mark statements in code, typically used with loops or switch statements.

13. exactOptionalPropertyTypes: When true, this flag ensures that optional property types are exactly checked. This means that an optional property declared as foo?: string can only accept string or undefined, not null.

14. noFallthroughCasesInSwitch: When true, this flag ensures that switch statement cases do not accidentally fall through. In other words, it prevents execution from automatically continuing from one case to the next unless explicitly done with a break or return.

15. noImplicitOverride: When true, this flag requires that methods overriding a base class method be explicitly marked with the override keyword. This helps catch errors where a method is intended to override a base class method but does not.

16. noImplicitReturns: When true, this flag ensures that all code paths in a function return a value, preventing potential undefined return values.

17. noPropertyAccessFromIndexSignature: When true, this flag disallows property access for non-existent properties in object types that have index signatures. This helps catch typos or misuses of property names.

18. noUncheckedIndexedAccess: When true, this flag ensures that accessing properties via an index signature is type-checked, adding undefined to the type if the property might not exist.

19. strictBuiltinIteratorReturn: When true, this flag ensures that built-in iterator return types are strictly checked. This is particularly useful for ensuring correct types with iterators and generator functions.

20. strictFunctionTypes: When true, this flag enables stricter checking of function types, ensuring that the function parameters and return types are compatible and properly validated.

21. useUnknownInCatchVariables: When true, this flag changes the default type of catch clause variables from any to unknown, which provides better type safety and forces more explicit error handling.

Enabling these strict flags can help you catch potential issues early and ensure your code adheres to best practices. For more detailed explanations, as well as examples, the documentation can be found here: https://www.typescriptlang.org/tsconfig
 
 If you are migrating to TypeScript, you can find assistance here: https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html

TypeScript: The Thing About ‘any’

The thing to know about the ‘any’ type, is that it will turn off type checking. That is by design. However, that really defeats the purpose of using TypeScript.

TypeScript 3.0 (2018) introduced a new type ‘unknown’. Per Microsoft, “any value is assignable to unknown; however, unlike any, you cannot access any properties on values with the type unknown, nor can you call/construct them. Furthermore, values of type unknown can only be assigned to unknown or any.”

If you have code with types ‘any’ it should really be defined as ‘unknown’.

Strict, but…

Even with the TypeScript strict mode enabled, the JavaScript runtime may return any in the following scenarios:

  1. Dynamic property access: When accessing properties dynamically using bracket notation (obj[prop]), the return type is often inferred as any.
  2. JSON parsing: When parsing JSON data using JSON.parse(), the resulting object’s properties are typically typed as any.
  3. Third-party library returns: Some third-party libraries may return values with an any type, even if you’re using strict mode.
  4. DOM manipulation: When working with the DOM, some properties and methods may return values with an any type.
  5. IndexedDB and other storage APIs: When interacting with storage APIs like IndexedDB, the returned values may be typed as any.
  6. Web Workers and cross-origin communication: When communicating with Web Workers or across origins, the data received may be typed as any.
  7. Older browser APIs: Some older browser APIs may return values with an any type, even in strict mode.

Keep in mind that these scenarios can vary depending on the specific JavaScript environment, library, or framework you’re using.


Angular Strict Mode

In Angular, enabling strict mode helps catch errors early and improve code quality. Here are the main flags you can use to enable strict mode in Angular, in the tsconfig.json file:

  1. strict: This is the main flag that enables all strictness checks in Angular. When set to true, it turns on several other strict flags.
  2. strictTemplates: This flag enables stricter type-checking for Angular templates. It ensures that component/directive bindings are assignable to their @Input()s and obeys TypeScript’s strictNullChecks flag.
  3. strictInjectionParameters: This flag ensures that dependency injection parameters are type-checked correctly.
  4. strictInputAccessModifiers: This flag ensures that input properties of components and directives are properly typed and accessible.

When strictTemplates is True, the following strict flags are set to true.

  1. strictInputTypes: Whether the assignability of a binding expression to the @Input() field is checked. Also affects the inference of directive generic types.
  2. strictInputAccessModifiers: Whether access modifiers such as private/protected/readonly are honored when assigning a binding expression to an @Input() If disabled, the access modifiers of the @Input are ignored; only the type is checked.

This option is false by default, even with strictTemplates set to true.

3. strictNullInputTypes: Whether strictNullChecks is honored when checking @Input() bindings (per strictInputTypes). Turning this off can be useful when using a library that was not built with strictNullChecks in mind.

4. strictOutputEventTypes: Whether $event will have the correct type for event bindings to component/directive an @Output(), or to animation events. If disabled, it will be any.

5. strictDomLocalRefTypes: Whether local references to DOM elements will have the correct type. If disabled ref will be of type any for <input #ref>.

6. strictLiteralTypes: Whether object and array literals declared in the template will have their type inferred. If disabled, the type of such literals will be any. This flag is true when either fullTemplateTypeCheck or strictTemplates is set to true.

7. strictSafeNavigationTypes: Whether the return type of safe navigation operations (for example, user?.name will be correctly inferred based on the type of user). If disabled, user?.name will be of type any.

8. strictDomEventTypes: Whether $event will have the correct type for event bindings to DOM events. If disabled, it will be any.

9. strictAttributeTypes: Whether to check @Input() bindings that are made using text attributes. For example, <input matInput disabled=”true”> (setting the disabled property to the string ‘true’) vs <input matInput [disabled]=”true”> (setting the disabled property to the boolean true).

10. strictContextGenerics: Whether the type parameters of generic components will be inferred correctly (including any generic bounds). If disabled, any type parameters will be any.

The Angular options object, angularCompilerOptions, is a sibling to the compilerOptions object that supplies standard options to the TypeScript compiler.

Here’s an example tsconfig.json with all these strict options enabled:

{
“compilerOptions”: {
“strict”: true}

“angularCompilerOptions”: {
 “strict”: true,
“strictTemplates”: true,
strictInjectionParameters”: true,
“strictInputAccessModifiers”: true}
}


TypeScript ‘@types’

TypeScript was first released by Microsoft in 2012, generating excitement among developers seeking a more maintainable and scalable way to build JavaScript applications. However, its adoption was initially hindered by a lack of type definitions for popular JavaScript libraries. In response, Boris Yankov created DefinitelyTyped, a community-driven repository of type definitions, in 2012.

By 2014, Microsoft and the DefinitelyTyped team collaborated to integrate type definitions with the npm registry, introducing the @types scope, which enabled easy installation and management of type definitions using npm. This led to the migration of the DefinitelyTyped repository to the npm registry in 2015, with packages renamed to follow the @types/<package-name> convention.

If you want to learn more about type definitions, check out the Typescript Typings course at Angular University.


Leveraging Strict Mode for Enhanced Compilation and Performance

This article has emphasized the importance of implementing strict type checking to mitigate bugs and unintended behavior. While primarily benefiting developers by encouraging cleaner code, strict mode also indirectly assists compilers/transpilers:

Improved Optimization
Inlining:
Replacing function calls with their actual code.
 · Constant Folding: Evaluating constant expressions at compile time.
 · Dead Code Elimination: Removing unused code segments.

Memory Management
· Reduced Memory Leaks: Mitigating memory leaks caused by delete statements or with statements.

Security Enhancements
 
· Improved Security: Preventing security vulnerabilities arising from eval statements or with statements.

Code Optimization
 
· Enhanced Minification: Enabling more effective code minification by removing unnecessary code and variables.

Benefits in Specific Environments

Angular

· Better Template Type Checking: More thorough template type checks, catching errors earlier.
 · Optimized Dependency Injection: Improved dependency injection optimization, reducing the risk of circular dependencies.

TypeScript

· Enhanced Type Checking: Stricter type checks, catching potential errors at compile time.
 · Improved Code Generation: Enabling the compiler to generate more efficient JavaScript code.

General Benefits

· Reduced Errors: Preventing common errors like null pointer exceptions through stricter type enforcement.
· Enhanced Maintainability: Promoting better coding practices for more maintainable and less error-prone code.

Embracing strict mode across Angular, TypeScript, and JavaScript, developers can significantly improve code quality, reduce errors, and enhance overall application performance.

The Bottom Line

Enable Strict in JavaScript
Add “use strict”; at the top of your JavaScript file:

"use strict";
// Your code here

Enable Strict in TypeScript
You can enable strict mode by adding “strict”: true to your tsconfig.json file, or by using the — strict flag when running the TypeScript compiler.

{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,

"allowUnreachableCode": true,
"allowUnusedLabels": true,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"strictBuiltinIteratorReturn": true,
"strictFunctionTypes": true,
"useUnknownInCatchVariables": true
}
}

Enable Strict in Angular
Angular strict is a combination of TypeScript strict and Angular strict flags. You can enable strict mode by adding “strict”: true to your tsconfig.json file Compiler Options (TypeScript) with 3 additional flags set; PLUS

{
"compilerOptions": {
//This is TypeScript Compiler
"strict": true,
//These are enabled with strict switch
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,

//These are added for new Angular strict projects
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true}


"angularCompilerOptions": {
"strictTemplates": true,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true}
}
Scroll to Top