Annotations and Assertions 12 exercises
solution

Preventing 'any' Type Issues from Global Typings

Functions like JSON.parse() return any by default. This is why the @ts-expect-error directive doesn't find an error when trying to access obj.c in the test case.

Solution 1: Typing the Object

In order to solve this challenge, we need to make sure that the any type on obj is suppress

Loading solution

Transcript

00:00 So the thing I wanted to draw your attention to here is the fact that functions like json.pass return any in your codebase. And so it's very easy for us to look at getobj and actually, accidentally by using it, introduce more anys into our codebase than we're expecting.

00:16 Because if we look here, obj is now of type any. This means that we can access anything on it, we can actually do anything with it. And we've kind of shut down type checking in various parts of our codebase just by calling this function. So this is a little bit dangerous. Now, how do we solve this?

00:35 Well, we need to make sure that this any on const obj is suppressed. We need to make sure that this any is not going to come out into our codebase and, you know, scare people, right? It's not going to, like, ruin our type safety across our entire app. So the important thing is to type it.

00:52 So we can say const obj is a number b number. And because we're assigning something to a slot that's already typed as any, it's not going to complain at us. It's not going to say, okay, you can't do this because any is not assignable to this. Because any is assignable to anything, we can just override the type.

01:10 And now obj is typed properly as a number b number. But if you think about json.pass, even this is unsafe. Because if we actually accidentally change this code here, it's not going to yell at us until we get to the runtime point here. So we probably need some more kind of runtime protections against this,

01:30 especially if we're passing json that we just get from local storage or something or from an unknown source. Then it's really kind of dangerous. So if we look at the second solution here, I've built a library called ts-reset. And what ts-reset does is you can uncomment this line, install it in your projects,

01:48 and it will basically override some of the global typings for various functions. And so now json.pass, instead of returning any, it actually returns unknown. And as we know from unknown, you actually need to narrow this down in order to get decent typings from it. And this means that your apps are going to be a lot safer,

02:06 because you won't get accidental anys coming in and clouding all through your application and kind of ruining your stuff. You're going to be working with a lot more unknowns instead. And then you can use a library like Zod, which I've got a free tutorial on on totaltypescript.com. Or you can use just plain old narrowing here.

02:25 So you can use an if statement, use like if a in obj, then return a. So this, I think, is a lot safer. And what I want you to bear in mind, though, is that, sure, the global typings use any. And you may also be using third-party libraries that use any.

02:42 But the important thing is to make sure those anys don't flow through your application and infect other parts of your app. Because when you have anys flowing through your app, it can get really destructive to your productivity with TypeScript, because you're just going to lose a ton of autocomplete, and you're not going to be able to catch bugs consistently.

03:00 So json.pass can often be a little bit of a, I don't know, like a heat point for that, right? It can attract a lot of anys and pull them into your code base. So it's important to make sure that you catch those fast and use ts.reset to turn them into unknown if you want to.