Make TypeScript Class Usage Safer with Strict Property Initialization

Rares Matei
InstructorRares Matei

Share this video with your friends

Send Tweet
Published 4 years ago
Updated 3 years ago

By setting the strictPropertyInitialization flag in the .tsconfig file, TypeScript will start throwing errors unless we initialize all properties of classes on construction. We’ll explore how you can fix the errors by assigning to them directly or in the constructor body. And if you can’t initialize directly but you’re sure it will be assigned to at runtime by a dependency injection library, you can use the definite assignment assertion operator to ask TypeScript to ignore that property.

Instructor: [00:00] Here, I have a class library, with a single property titles, that's of type array of string. Right below here, I am creating a new instance of that class. This very simple, it's quite obvious that the title's array has not been initialized and it's undefined.

[00:14] However, let's assume that our app is a lot more complex, and somewhere else in my codebase, I am trying to use my library instance to get the titles from it, and then filter through them.

[00:25] Now, if I open up my terminal and I try to run the generated JavaScript, I get the type error saying, "Cannot read property filter of undefined." I'll close the terminal and go to my tsconfig options.

[00:37] In TypeScript 2.7, there's a new flag called strictPropertyInitialization, that will warn us about these types of problems at compile time. For it to work, we'll also need to enable the strictNullCheck flag.

[00:52] If I go back to my file now, we'll see there's a problem on our title's array. What TypeScript is saying now is I can see the title's array as of type array of string, but the type array of string is different from the type undefined. It cannot be undefined.

[01:09] Because I don't see it being initialized anywhere, I'll just have to throw an error. This is why we need to enable the strictNullChecks flag for this to work, because it essentially enables the separation between undefined, or null, and all other types.

[01:26] For a simple fix, I can just add or undefined to the type declaration. Now, the error has moved to this usage point below. Because I've said titles might be undefined, it's not really 100 percent safe to let the developer call the filter function on it. To fix this, I'll need to guard against undefined, and I can simply wrap it in an if.

[01:51] Now, this is great. By simply enabling this flag, I'm now guarded against so many potential runtime errors, but adding undefined checks everywhere we use instances of this class might become cumbersome. Another option is to just initialize the property directly in the class to some default value.

[02:11] Now, I can just remove the undefined because I know it's going to be initialized from the beginning. I can also initialize it in the constructor. This will also make the error go away, as we are still guarantying that upon initialization, all properties of this class will have been assigned.

[02:27] If there is the slightest possibility that titles might not be initialized, say for example the libraries undergoing renovation, TypeScript will notice and break compilation again. To fix this, we can just make sure it gets the value in every possible branch.

[02:44] Finally, we might be using a dependency injection library that we know will initialize all of these classes' properties at runtime. In that case, we can just start an exclamation mark after the properties' name. This is called the definite assignment operator. It's a way of telling TypeScript that this property will definitely be initialized.

[03:04] Keep in mind that now we are back to square one in terms of the compiled time protection we get from TypeScript. This is still going to throw an error, now. Still, at least by having to explicitly add the sign to each property, it does make developers think extra carefully about potential unsafe usages of properties they add.

[03:26] To recap, we've had to look at how enabling the strictPropertyInitialization flag gives us more confidence when using instance properties and eliminates a lot of potential runtime errors.

[03:39] Once enabled, we can start writing classes by either initializing the properties directly, initializing them in the constructor, or by adding the definite assignment operator.

Pavlo Kochubei
Pavlo Kochubei
~ 4 years ago

Great tip. You can also use strict: true, which is a shorthand for enabling: noImplicitAny, noImplicitThis, alwaysStrict, strictBindCallApply, strictNullChecks, strictFunctionTypes, strictPropertyInitialization.