What is a type assertion?

There are scenarios where you know that a type is not undefined or null but that TypeScript will hint that it might be. When this happens, you can perform a check against undefined or null and within the closure of the condition will be a guarantee that the type is not nullable. However, three scenarios can benefit from having a shorter syntax.

The first scenario is with a deep-nesting object. In that case, you may have several levels of nullable fields and if you are sure that they are not undefined or null, this will be great to avoid having a nested if structure:

interface T1 {
myNumber: number | undefined;
}

interface T2 {
t1: T1 | undefined;
}

interface T3 {
t2: T2 | undefined;
}

const myObject: T3 | undefined = {
t2: {
t1: {
myNumber: 1
}
}
}

if (myObject !== undefined) {
if (myObject.t2 !== undefined) {
if (myObject.t2.t1 !== undefined) {
if (myObject.t2.t1.myNumber !== undefined) {
console.log("My number is :", myObject.t2.t1.myNumber);
}
}
}
}

The conditional check is the safest way to ensure that nothing is undefined. However, in some cases, the check may have been made prior to accessing the data, but an access to the value is needed outside the scope of the check, which makes TypeScript nervous about if meanwhile, the state has changed. That would be the case if we tried to access myNumber right after the previous code. This is where assertion type comes into play. A assertion type is the bang operator, or exclamation point, after a member that specifies that the member is not null or undefined. You are asserting that this is the case and take the responsibility to un-undefined or to un-nullable to field.

It means that you can access the member by using a single line:

console.log("My number is :", myObject!.t2!.t1!.myNumber);

It is crucial to understand that this can lead to a potential runtime error if used at the wrong time. For some reason, any nullable field can become nullable if applied at the wrong time or place. There is no guarantee that the execution will succeed but will soothe TypeScript error saying that you are accessing a nullable field without narrowing it down to the type.

The second case of using type assertion is when you are defining a field in a class. If TypeScript is set to have the compilation strictness to avoid an uninitialized field, then you will have an error when defining a field and not specifying a value at the declaration or in the constructor. This is a great validation, but, in some rare cases, the value may come later in an initialize function. In that case, you can assert the class's field to say that you are taking care of the value:

class LateInitialization {
m1!: number; // Not initialized (use type assertion)
constructor() {
// No initializing here
}
public init(): void {
this.m1 = 1;
}
}

Once again, this should be used with parsimony, because it can bring some issues. For example, you can now access the member and use it without TypeScript validating that the value was assigned before accessing the value:

constructor() {
this.m1 + 1; // This will fail
}

This might seem like a trifle, since you know that you will not do such a thing. But it can be less obvious. A case of error is that you are accessing the member from another public function that might be called before the init function causing any usage of the variable to be undefined. Type asserting forces TypeScript to close its eyes about uninitialized value.

The last scenario is also dangerous to use and should be coded only with a lot of care. You can at any time use the exclamation point to erase the nullability. It means that it works with a simple variable as well. The following code declares a variable of type string or undefined. It sets its value using a function that is immediately invoked. The function has a return type of also string | undefined. TypeScript concludes that this function may return one or both types, and hence could legally return something undefined. However, we know that it is not the case, and hence can use the exclamation point to remove the undefined possibility and use the string's functions:

let var1: string | undefined;
var1 = ((): string | undefined => "Not undefined but type is still both")();
console.log(var1!.substr(0, 5));

Again, this is dangerous and a better way around it could be employed. The first thing is to avoid having a union with undefined or null. If this is out of your control, avoiding functions such as one of the last code examples that aslo return undefined. The same code with the return type of string would have solved the problem gracefully.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.129.216.7