This is why you need TypeScript type guards in Angular

preview_player
Показать описание

We take a look at four different approaches to dealing with potentially null values in Angular, ending in creating a generic type guard that we can use to assign a type to any object on the condition that it has no null values.

0:00 Introduction
0:15 The problem
1:01 Type assertion
1:45 Manual check
2:31 Type guard
4:23 Generic type guard

#ionic #angular

Рекомендации по теме
Комментарии
Автор

I am sorry to disagree, but A and S solutions are much worse than B. They are not typesafe, error-prone, and provide a false sense of correctness. Only use a more complicated solution if you can write their type correctly.

No better proof of this is that you are misusing it: the formValues variable you pass is typed as Partial<{title: string | null}>, but your typeguard "converts" it to {title: string}. If all the other types are defined correctly, the formValues can be {}, which is a Partial<{title: string | null}>, but nonNullChecklist will accept it happily.

A more obvious example is that nonNullChecklist({name: "not-a-title"}) will be incorrectly accepted as a safe AddChecklist value.

The generic nonNullObject has the same problem. And on the other hand, it is not the nicest API for its consumer if you have to specify the T type at every call. Even worse, there is basically no check of the type parameter. You can call with an add checklist form value by mistake, and introduce a non-obvious runtime bug which would have been easily caught compile-time if the B solution is used.

A much better typed version of your generic function could be like this:

type NonNullValues<T> = {
[K in keyof T]: Exclude<T[K], null>;
};

function nonNullValues<T>(object: T): object is NonNullValues<T> {
return => value !== null);
}

This type signature eliminates the issues I mentioned above and has a more consumer-friendly interface because no need to specify the type parameter at the call, T can be inferred automatically. If you pass a {title: string | null}, it will guard it to {title: string} without specifying any type, and only if all its values are non-null.
And using this version, you discover the bug in the code that you did not handle the partialness of formValue. Then you either guard against the Partial<T> somewhere else or enhance the implementation, the type, and the name of this function.

(I did rename the nonNullObject to nonNullValues, it is more descriptive because you are not actually checking the object for null but its values)

kndztr
Автор

Very nice approach I like it made my day useful, because learned something cool

icoz
Автор

How about undefined values? In my case, I use to check both null and undefined type. Great stuff and thanks.

lcho
Автор

Ah yes, I was really excited to see this video, since the tip in the last newsletter. Not disappointed: not only did I learn about the guards, but I also learn about the Partial type of Typescript, I didn't even knew the existence of. And I now feel silly, thinking about all thoses objects with every properties nullable, created for forms...

Thanks for always expanding my knowledge with your videos, can't wait for the next one :)

WanderingCrow
Автор

I always ended making a custom TypedFormGroup<T>, TypedFormControl<T> etc...

But now Angular 14 comes typed

neociber
Автор

Right now, in Angular 14 we have typed forms, and u can also create form simply like this.fb.nonNullable.group... etc ;) Isn't it enough?

mkez
Автор

Hey Joshua, appreciate the work. Can "nonNullablecheck" be written in function declaration style? I am having a hard time understanding "checklist is AddChecklist" here

prateekvaidya
Автор

Hi. Reactive and template driven form. Which one is better?

phuongtran-qhkq
Автор

Can we also make that guard predicate reusable. I mean you always check it is null or not but maybe in other case I want to check the property is present or not to check the type, then we can not use this guard. So, we can pass callback as a second parameter and use this as predicate. What do you think ? But Checking type inside if with passing callback will be weird though 🤔

sourishdutta
Автор

Thanks for another good tip. In this particular example, can't you just do normal form validation check before adding title to the service?

JensChristianLarsen
Автор

We can go even further and use either monad for error handling

MichalSmolinsky
Автор

Nice tips. But imma gonna go with "B" tier... "A" and "S" make my head hurt 😆, and I imagine makes the code a bit harder to read for other devs not familiar with this technique

JBuchmann
Автор

Shouldn't Object.values method return array of characters, for string. Or I'm wrong?

noss
Автор

This is applicable only where all the form values are expected to be non null…which in most cases is not the expectation…

kandeepasundaram
Автор

For your form example couldnt you just use the NonNullableFormBuilder instead of the formbuilder or pass for the title the option nonNullable: true

AnotherCookingChannel
Автор


Aside from forms in TypeScript there's a util for NonNullable<Type> that I actually have not used much, I wonder if there's some good practices involving that util.

StephenMoreira
Автор

To A and S: values can still be undefined

robrabbit