Annotations and Assertions 12 exercises
solution

The "as" and "as any" Keywords in TypeScript

The error we encountered in this challenge was that the EventTarget | null type was incompatible with the required parameter of type HTMLFormElement. The problem stems from the fact that these types don't match, and null is not permitted:

const data = new FormData(e.target); //
Loading solution

Transcript

00:00 Okay, let's dive deeper into this area, try to work out what's happening. We can see that new form data requires a HTML form element. This is coming from, again, the DOM typings. And so we can see E.target here. It's basically saying argument of type event target or null is not assignable to a parameter of this type. So first of all, we can look at this and we can say,

00:19 okay, type null is not assignable to HTML form element. So you can't pass null into here. If I were to just pass null, then I would get a similar error. So it would just say argument of type null is not assignable to this. So first of all, we need to say that E.target is not null. So what we could say, this type, if we hover over it here,

00:38 it's an event target. So we could use something interesting here. We could say E.target as event target. Now what as does is it's basically saying this thing at this position, E.target here, we're basically forcing it to be something else.

00:57 And we can see here though, that this isn't working still. Argument of type event target is not assignable to the parameter of type HTML form element. We happen to know that this code is working. It's working at runtime. It's got tests covering it. So what we could say is E.target as HTML form element.

01:15 And notice here, the error now goes away. E.target is now being, even though it's inferred at this position as event target, if we copy this out into its own field here, or own variable, const target equals E.target as HTML form element. Tests are still passing

01:31 and now target is being inferred as HTML form element. How did this happen? This, it's like we're removing some information from TypeScript or kind of, maybe that's the wrong metaphor. What we're saying here is without this annotation, TypeScript is going to infer this as an event target.

01:49 But by saying as HTML form element, we say, no TypeScript, you're wrong. This is actually a HTML form element. We're gonna look at some of the limitations of this going forward, but what we're basically doing is lying to TypeScript or telling it a little white lie so that we can get our runtime working.

02:08 Now, if you can't be bothered to go through that whole process, then there's another way you can get this working even faster, and that is to use any. Now we looked at any a while ago, but as any is often a way that you can basically say, okay, I don't really care what type this is. And at this point, I don't need to know about HTML form elements.

02:28 I can just say E.target as any. And of course, then I can actually just inline this. So I'll just say, oops, where's the thing? Here we go, inline variable. And now we've got E.target as any in that slot. So as any kind of acts as a way of suppressing

02:46 TypeScript errors at this particular point. We're gonna look at a few different caveats with this and how this can spill out and actually cause more bugs. But at this point here, E.target really is just, just being passed directly into this function. And it means that you don't need to worry about that too much.

03:06 But if you have a choice between saying, okay, E.target as any and E.target as HTML form element, this is generally the one you want. You want the more specific one, because this says to TypeScript and to any devs looking at this, this is what I wanted E.target to be.

03:23 Because as any, it sort of doesn't reveal any intention as to the bug you were even trying to fix in the first place. And code bases that I've seen in the wild can contain a lot of as any, just to really patch over TypeScript errors. So you really want to be using it in a very careful way

03:42 and making sure that the thing that you're actually doing is solving the error instead of just making the error go away. So in this case, as HTML form element makes sense, because you're saying to TypeScript, I know more than you about what E.target is going to be. So as is a crucial tool in your tool set,

04:01 because it means you get to annotate with intention, tell TypeScript that you know more than TypeScript does, but you shouldn't be using it as your default way to annotate.