Strict TypeScript Isn't Enough Anymore

Web Dev Simplified| 00:21:24|Mar 24, 2026
Chapters5
The speaker argues that enabling strict mode alone isn’t enough in TypeScript and promises to show over 15 TS config options to catch every error, while also promoting an updated TypeScript course.

Strict TS alone isn’t enough—Web Dev Simplified shows 15+ TS config tweaks to catch every error and keep code clean.

Summary

Web Dev Simplified’s video dives deep into the gaps left by just turning on TypeScript’s strict mode. Andy explains that even with strict true, real-world projects often miss errors because the default configuration isn’t aggressive enough. He then walks through 15-plus TS config options that actively warn about issues the bundlers might overlook, from path aliases to strict checks on arrays and object indexing. The tutorial includes practical, concrete examples—like using path aliases to replace brittle relative imports and enabling no unchecked index access to catch out-of-bounds access at compile time. Along the way, Andy highlights features that are optional but highly useful, such as no implicit override for class methods and erasable syntax only to prevent TypeScript from generating non-removable output. He also touches on migrating JavaScript to TS with allowJs and checkJs, and teases updates to his TypeScript Simplified course that cover advanced topics like type programming in libraries such as TanStack, Zod, and Drizzle. If you’re looking to raise your TS game from beginner to senior level, this video not only lists the configurations but also explains why each one matters. Don’t forget to check the course link in the description for the current price and access to deeper TypeScript features.

Key Takeaways

  • Enable path aliases (paths) to enable absolute imports relative to a root; use a prefix like &/ and map &/ to /src to simplify imports.
  • Set noLocalUnusedLocals and noUnusedParameters to true to catch dead code and unused function inputs early.
  • Enable noUncheckedIndexAccess to force TS to treat any array element access as potentially undefined, improving runtime safety.
  • Turn on noUncheckedIndexedAccess specifically for objects with dynamic keys to prevent typos in dot-access on index-signature maps.
  • Use noFallthroughCasesInSwitch to require explicit breaks or returns, preventing accidental fall-through and promoting clearer switch logic.
  • Enable noUncheckedExpression or noPropertyAccessFromIndexSignature to guard against misspelled or non-existent dynamic keys and properties.
  • Consider erasableSyntaxOnly when using TS features that emit extra JavaScript code (like enums or certain class field initializations) to keep output clean and maintainable in Node environments.

Who Is This For?

Developers who already know the basics of TypeScript and want to harden their configs. Ideal for those migrating from JS to TS, or building libraries and large apps where subtle type mistakes slip through the cracks.

Notable Quotes

"Most developers think that enabling strict mode in Typescript is enough to solve all of their problems."
Sets up the premise that strict mode alone misses many issues.
"I’m going to show you over 15 different configurations you can set up in your TS config to warn you of every single possible error."
Central claim of the video with the promised breadth of options.
"No local unused locals. And we’re also going to come in here with no unused parameters as well."
Intro to the first quality-of-life TSConfig checks.
"This is a esoteric feature inside of JavaScript called labels that work like a go-to statement."
Explains a lesser-known TS check involving labels.
"No fall through cases in switches. We’re going to set that to true as well."
Demonstrates preventing switch case fall-through.

Questions This Video Answers

  • how to configure TypeScript to catch all errors beyond strict mode
  • what TSConfig options should I enable for safer arrays and objects in TS
  • how to migrate a JavaScript project to TypeScript with checkJs and allowJs
  • what is noUncheckedIndexAccess in TypeScript and when to use it
  • how to prevent switch case fall-through in TypeScript with noFallthroughCasesInSwitch
TypeScriptTSConfigPath AliasesNoUnusedLocalsNoUncheckedIndexAccessNoFallthroughCasesInSwitchIndex SignaturesCheckJSAllowJSErasure in TS
Full Transcript
Most developers think that enabling strict mode in Typescript is enough to solve all of their problems. But this file on the left here is absolutely full of type errors, but not a single one is getting an error or warning. That's why I'm going to show you over 15 different configurations you can set up in your TS config to warn you of every single possible error. And many of these are things that you will not see in normal bundlers or setups, but they are crucial for making sure your TypeScript code is written the best that it can be. Also, I just updated my TypeScript simplified course to add a ton of new really advanced TypeScript features. So, now you can go all the way from a beginner up to a senior level TypeScript developer in this one course. Just know that the price will be increasing soon. So, make sure if you want to get it at the lowest price possible, that you use the link down in the description below because the price will be increasing in just a few days. Now, as I've said, this course will help you go from a beginner just how you can set up TypeScript all the way through the basics to more complex features, things like generics, all the way up to the really advanced things like type programming, which is what is used to build libraries like Tanstack, Zod, and Drizzle. This is the stuff that almost no course touches cuz it's incredibly complex and difficult. But I've simplified in a way that makes it easy to understand so that you can write as complex of TypeScript as you need. So again, if you want to learn everything from the very beginning all the way up to the super advanced TypeScript features, get the course now before the price goes up. It'll be linked down in the description below. Now, jumping straight into our configuration options. I'm not going to be talking about anything related to strict mode. I assume that strict true is set in any TypeScript project you're working on. And if it's not, you should definitely enable this. So, I'm not mentioning anything related to strict mode or the settings that it turns on. These are all additional things you can add on top. And the very first one actually doesn't change any of your type checking. It just makes working with TypeScript so much easier. And that is the path alias. So I can come in here and type in paths. And this essentially allows me to create custom paths in my import statements which I generally use to make absolute imports possible because normally in Typescript or React or JavaScript or whatever language you're using, you can only import relative imports. That means this thing which I am importing, you can see if I in this deeply nested folder right here, nested deeply main, I want to import something from the root file right here. In order for me to do that, I need to essentially use these relative imports to go backwards a few files to get to this location. This is a huge pain because now if I want to move this file or copy code, all of my imports need to be reconfigured to work with the relative syntax for the new location is. This is why paz is really useful because I can come in here and I can specify a custom alias. Generally, this alias can be whatever you want, but I like to just do an amperand followed by a slash followed by a star. That means I can start any import with amperand slash and it's going to assume the import is from a specific location. Here is where you specify the location and it's inside of an array because it could look in multiple places. But in our case, I want to look inside my source folder cuz I have this source folder right here that all my code is inside. So I want all my imports to be relative to that source folder. So I can just say dot /source slash and then I can put a star at the end. And now every time I type in amperand slash, it's going to replace that with slashsource slash. So it allows me to do absolute imports relatively to whatever file I'm inside of. So now I can take this entire import and replace it with at slash and it's going to give me the exact same import. It gives me that root file just like it was there before. And that's because of this path alias. And you can call it whatever you want and point it to whatever location you want. For example, if you have a folder inside your project that you import from a lot, maybe it's a components folder, you can have an alias import called like at components or whatever you want. I like to have some type of symbol in the front. And you can have that point to wherever your components folder is. Maybe it's like super nested inside of some other random folders like this. And essentially, it'll replace this text over here. If we just come in here with that slash star at the end of both of these, there we go. It'll replace all this text over here with all the text on this side to make your alias imports a little better. But like I said, I mainly do this just to have one root alias that I can use to make it so I can import absolute paths as opposed to relative paths. Now, these next couple settings I want to talk about are all about helping you with writing cleaner code and cleaning up your code as you're going. The first one is going to be no local unused locals. There we go. We're going to set that to true. And we're also going to come in here with no unused parameters as well. We're going to set that to true. All that these settings do is they force it that anytime that you have a local variable or a parameter in a function that has not been used, it's going to give you a warning. So you can see here we haven't used this root variable. These functions aren't being used anywhere. So I get underlined. And you can see this C parameter is also not being used inside of our function. So we get a nice little underline squiggle for that function as well. So the locals one is essentially every variable that's not a parameter. And then this parameter one does the same exact thing for parameters. I see absolutely no reason to have this disabled because if you're not using a parameter, it most likely means that it's because there's a typo in your code or something like that or you just forgot about this and now you need to remove it because you're no longer using it. So, I really love having those in place. The next ones I want to talk about are also kind of similar and that they help you with typos and cleaning up your code a little bit. The first one is going to be allow unused labels. We're going to set that to true. And if we take a look at what this does, if we scroll down into our code, we're actually going to get an error right here on this line. And actually, I should set this to false because we don't want to allow unused errors. There we go. So now, when I set that to false, we're going to get an error right here. And this essentially is a esoteric feature inside of JavaScript called labels that work like a go-to statement. If you don't know what that is, that's perfectly okay. It's a really bad programming practice that you can technically do inside of JavaScript, but it's a feature that you are probably never going to use. And if you have code that's using these labels, it most likely means you made a typo. oftentimes you're trying to create an object and you accidentally put one of your key value pairs outside the object. So in this case, this name is supposed to be inside of our user object, but I accidentally put it in the wrong place. So now if this un allow unused labels is set to false, I'm going to get a warning cuz technically this is valid JavaScript code. This is a label in JavaScript, but that's not what we want it to be. We want it to specifically be a property inside of our object. So this gives me a warning helping me know, oh, I accidentally made a typo with this. I should put it in the correct location. Speaking of helping with typos, this next one is super important. And this one is no unchecked side effect imports. We're going to be setting this to true to make sure that we have this. And if we scroll up, we're going to get an error on this analytic right here. And that's because sometimes you can import a file that has side effects. So if we look in this analytics file, all it does is it logs out whatever we want. But oftent times if you're importing like analytic software, other things, you may import a file, but not actually import anything from it. You just import it so it can run the code inside of it before the rest of your code runs. But if you have a typo in your file name, for example, this file is called analytics with an S at the end, and I'm importing analytic with no S at the end. I want that to give me an error saying, "Hey, I'm importing something that doesn't exist." If you don't have this setting enabled, you aren't going to get any warning. It's just going to fail silently because it's not importing anything and it'll just show up and not even care. But if you add this setting in there, it will give you a warning inside your code essentially saying, "Hey, you're trying to import a file that doesn't exist, so I see no reason not to have this enabled." Another no-brainer in my opinion is to have the feature of no fall through cases in switches. We're going to set that to true as well. Essentially, this helps you when you're using switch statements. And if we scroll down here, you'll notice I now get these warnings on my cases here for my switch statement for the success and error. And that's because whenever you have a switch statement, if you don't have a return statement or a break statement inside your switch, it's going to keep running all the code until it gets to the very end of your switch statement. So, in our case, in a status of success, it'll run log success. it'll log out error and it'll log out unknown status because I'm never stopping my case from ending. This just prevents you from doing that. If you forget to put that in, it's going to give you a little warning because 99.9% of the time you don't want to have fall through cases. And if you do want to, for example, do the same thing for success and error. What we can do is we can write them like this. And now it's going to combine those together into one statement essentially. So it still works when you want to combine things together. The only time it doesn't work is if I wanted to run this code and then follow it by running this code. But again, 99.9% of the time, that is not what you want to do. So, this warning just helps you solve that. And now I can come in here and I can put my break statement on every single one of these to make sure I don't have that issue. Now, the last setting in this no-brainer category that I think everyone should have enabled is just the allow unused or unreachable code. We want to set that to false. Essentially, anytime that you have code that it's impossible to get to, for example, this returns before we get to this log here. It's just going to get me a warning saying, "Hey, this code's not reachable. you probably want to completely remove this code from your codebase because it doesn't actually do anything. So, these are the really simple no-brainers. This one I love because it just really helps you with writing your code. The rest of these just make sure that you don't make really simple mistakes or have extra code that you don't need. Now, this next category I call optional, but highly suggested. And this is where we get some of the really more interesting features in Typescript that you don't necessarily need, but I find they enhance my TypeScript when I write these features. This first one is a huge favorite of mine and this is no unchecked index access. And we're going to be setting this to true. And essentially what this does, if we scroll all the way to the very bottom, we'll see an example of this. I have an array right here called numbers. And this numbers array is 1 2 3. And then I'm trying to access a value from that array. For example, I want to get the element at the 10th index, so the 11th element, and then convert it to a string. Normally, it would give me an error. If I don't have this setting enabled and I come over here, you're going to notice it's not going to give me any warnings or errors at all. Even though technically my code will give me an error when it runs because there is no 11th element. The whole idea behind no unchecked index access is that what it's going to do is anytime you try to access the index of an array, doesn't matter if you're accessing the first element or if you're accessing a massive element way later in your array, it's going to assume that that element could be undefined because it doesn't know if your array has three elements, if it has no elements inside of it. For example, here if it has a million different elements in it, it has no idea to know. So, it always assumes that undefined is a valid option. I like having this enabled because it again gives me extra type safety because it's very easy to say, oh, you know, I'm going to get the the fourth index element out of my array and I'm going to convert it to a string. But if your element or your array doesn't have that many elements, this will give you an error and TypeScript won't actually show it to you. So, I like to enable this working with my arrays just to give me a little extra type safety. It does add a very small amount of additional code that I have to write because now I have to make sure that I do an optional check here with that question mark syntax to get rid of the error. But I like having that because it prevents runtime errors, which are always a huge problem. The next one is kind of in the same vein, but it's for objects instead of for arrays. And this one is the no property access from index signature. I'm going to set this to true as well. And now, if we scroll up, we can see an example right here of what is going on inside of our code. Essentially, I have this settings object that allows me to p paste in a dark mode and a last save date and any custom settings I want. That's what this little bit of code right here does. Essentially, it says I can add any string as a key and it can have a value that's a string, number, boolean, or date. So, I can come in here, I can type something in, and as long as it's a string or a number or a boolean or a date, it's going to work fine. Now, if I tried to pass in something that wasn't one of those different types, it's going to give me an So, like if I try to put a function here, it'll give me an error, but it allows me to pass on custom properties. This is very common with things like settings configurations where you may have some hard-coded settings, but you don't know what the rest of your settings are going to be. In my case, I have this custom setting I want to save called username, and I'm saving that to WDS. And then down here, I'm accessing my custom setting, as well as accessing my dark mode. But you'll notice it's giving me an error cuz I accidentally spelled dark mode incorrectly. This is what this no property access from index signature does. If I disable this and I resave, you'll notice that this error on dark mode is actually going to go away. And that's because technically this is a valid key. And that's because according to my type, every single string is a valid key for my object. So it's just going to assume that I am typing in dark mod as a valid key for some other custom setting when in reality I most likely want dark mode instead. So what this setting does is when we reenable it, it essentially says, okay, if you are accessing a value of a object by typing it in using the dot syntax, it's going to force it to be one of the values you defined as a real value, not one of these custom ones right here. So it'll work fine if I have dark mode. It'll work fine if I have last saved. But if I spell either of those incorrectly or try to access anything else, for example, I try to access username, even though I know I put that on there right here, it's still going to give me a warning. The only way you can access custom settings is if you wrap them inside the index notation. You can see here I can pass username along. I can pass along dark mod if I wanted. All of those are going to work just fine. Now the reason I really like this is because again when I'm accessing something via dot notation, it's usually something I know exists. While if I want to access something custom, usually that custom thing is saved in a variable and I'm going to access it through this index notation. So, usually 99.9% of the time, my code does not change when I enable this setting. All it does is help me with any typos I have in my code. For example, I spell something wrong in my code. It'll give me an error for that. Now, the reason I have this in the optional category is because you may not want this feature because it does technically change how you write your TypeScript slightly, but I find that I already write my code like this, so it doesn't change anything for me. Now, the next one in this optional category here is going to be erasable syntax only. This defaults to false, but in the next version of TypeScript, it'll actually default to true. And I think this is a great idea for them to do. And the reason for that is because there are a few TypeScript features that technically modify how your code gets rendered. For example, if you create a class and inside your constructor you define what type that variable is going to be for private, public, or protected, it's going to change your code. Instead of just removing this private variable and letting your code run, you'll notice I now have a JavaScript error in my code. What happens when you write your code like this is it essentially takes this private deletes it and then it adds out here a new section with that name. So essentially it converts your TypeScript code from one thing to something else when it compiles in order to make it valid JavaScript because this code alone is not actually valid JavaScript. Same thing with enums. Enums convert to actual JavaScript code from this enum type. So it takes TypeScript code and converts it to real JavaScript code. So it changes what your output is. This erasable syntax only just prevents you from using anything that can't be erased erased from your code. So for example, if I erase this, all the places I use that enum are now broken. So I like enabling this because not only does it make it so that I can use TypeScript in Node because Node all it does is erase your types, it doesn't do any compiling, it's also making sure I don't use some of those weirder TypeScript features such as enums and so on that I find are really not good practice to be using. Now, this next category is for personal preference, and these are essentially things that you can take it or leave it entirely up to you. The first one I want to show is the one that I think makes a lot of sense, and it's called no implicit override. We're going to set that to true. This is really only useful if you're in a very heavy class-based object-oriented style of programming. You'll notice here that I have a box class which has a close function on it. I then have a popover that extends my box, and then I have a modal that extends my popover. And in my modal, I'm overwriting that close function. Now, this may be intentional or it may be a mistake, but if I don't enable this no implicit override, you're going to notice it's not giving me any warning or letting me know that I'm overwriting this closed function. I have no idea that this closed function is being overridden at all. So, the reason that you want to have this no implicit override is essentially what it does is it tells you that you're overwriting a function and forces you to be explicit when you want to do it. So, in our case, it says, hey, you're overwriting this close function. So, in order to make sure I do that, I just write the word override in front of it. And now I'm explicitly telling Typescript, "Yes, I meant to override this function." So if you're working very heavily with object-oriented programming and classes, this can help make sure you don't make accidental typos and override things that you didn't mean to. I think this is a no-brainer anytime you're using object-oriented programming, but it's entirely personal preference because I know a lot of people don't do that. Now, this next one is super simple and it's called no error truncation. We can set that to true. All that this does is if you have an error inside of your TypeScript code and you hover over your error and it shows you a bunch of information for what the type is. So like if I hover over this, it shows me a bunch of type information about the thing in my error, if I have this set to true, it'll show me the full type, no matter how big that type is, which can mean you get tons and tons of code being output in your type for certain things that are very large types. If you have it set to false, which is the default, it's going to truncate those types to make them a little bit shorter and easier to read. Now, this is one that I would normally just leave as false. But if you're debugging a really complex error and you want to see a little bit more information about the type that you're debugging inside the error, you can just temporarily set this to true, come over, look at the actual error, see the full type itself to maybe help you debug that problem a little bit more. And then when you're done, you can come back and turn it back to false or remove the setting because it's something that's really only useful for when you're debugging complex problems. And most of the time I like that truncation because otherwise your error messages can be absolutely massive. Now the final one in this personal preference section that I want to talk about is one that is definitely optional and it's you may not actually like it but this is the exact optional property types. So if we scroll all the way down, let's create a brand new type here called user two cuz I think we already have a user type and we'll just say that it has a name which is going to be a string and let's say that this is an optional property just like that. So now if I hover over my type for user 2, you can see we have our optional name which is set to a string. Now by default, if I don't have this exact property types set to true and I hover over my user 2, you can see that the name is not only optional but it also can be a string or undefined. This means when I define a user which given that user 2 type, I can set the name equal to undefined and that is going to work just fine. There's no errors in my code. If I enable this exact optional property types, I'm actually going to get an error in my code when I try to set this to undefined. You can see here the type undefined is not assignable to type string. I either need to leave name off entirely. That works fine. Or I need to specify it as a string. It essentially makes you be explicit that if something is optional, it means it does not exist on that object or it exists with the correct type. It can never exist on the object and be set to undefined. Now the only reason you'd want to use this is because there are certain things inside of JavaScript such as if you want to say if name in user. So this is checking is the name property in our user. Well, if the name is set to undefined, technically this still returns true because the name property is there. It just doesn't have a value. While if the name property is not there, this returns false. So this actually returns different things depending on if that undefined property is there or not. So this exact property types solves this potential bug for you because you can't set the property to undefined. So it's either there or it's not there. And if it is there, it has the correct type being assigned to it. That's pretty much the main use case for this. But you may use it for other things as well just to be a little bit more explicit. And this is probably the most opinionated of them. You can either take it or you can leave it entirely up to you. Now, this last section is specifically if you're working with a project that maybe uses some JavaScript or you're converting a JavaScript project over to a TypeScript project. And these are the settings of allow JS and the settings here of check.js. There we go. We'll set both those to true cuz that's what you want to do if you're slowly converting over a TypeScript project. And now, if we have a brand new file, we'll just call this one JavaScript.js if I can spell properly. And this JavaScript js file is just going to have some JS code inside of it. Let's say that we're going to export t equals 10. Doesn't really matter. And inside my main file, I want to import that variable. So we can say import t from and we can get it from that JavaScript file. Just like that. You can see everything is working perfectly fine. And that's cuz I have allow js set to true. If this is not enabled or it's set to false, I'm going to get an error inside my code when I try to import JavaScript code at all. So, let's just come in here and set that to false to be 100% explicit. And when I hover over this, you can see right here, T is declared and could not find a declaration file for at JavaScript. Essentially, it doesn't allow you to import those JavaScript files at all if you don't have this enabled. So, if you're slowly working on converting over, I recommend enabling this allow js just so it will let you import JavaScript files into your TypeScript. Now, check.js is really important because it'll allow you to actually type check your JavaScript code. For example, if I run parse float and I pass it in a number, this is going to give me an error because you can see here, this is supposed to take a string, not a number. That's what check.js does. If I have this set to false, it's not going to check this file at all. Now, most of the time, if you're working inside of a codebase with lots of JavaScript and you're converting it over, I recommend not enabling check.js and instead in every single file you want to do type checking, add a comment that just says at TS check. That way, you'll only type check specific files as you slowly go through them. So, this makes it a little bit easier to slowly migrate your code from JavaScript to TypeScript. Now, as I mentioned at the beginning of this video, I highly recommend you check out my TypeScript simplified course. Like I said, I just did a massive update adding tons of content specifically around really advanced TypeScript features. But even if you're absolute beginner, this course assumes you know nothing about TypeScript and works you all the way up to that senior level TypeScript developer that can write the same things that Zod, Drizzle, and Tanstack, and all those other really popular Typescript libraries can do. Currently, this is the lowest price you can ever get the course at because the price will be going up in just a few days. So, make sure that if you're interested that you check it out at the link down in the description below and get it at the slowest price possible.

Get daily recaps from
Web Dev Simplified

AI-powered summaries delivered to your inbox. Save hours every week while staying fully informed.