Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Unleashing the Power of TypeScript: Key Considerations in tsconfig

Sign upSign InSign upSign InMaksim ZemskovFollowLevel Up Coding--ListenShareIf you’re building complex web applications, Typescript is likely your programming language of choice. TypeScript is well-loved for its strong type system and static analysis capabilities, making it a powerful tool for ensuring that your code is robust and error-free. It also accelerates the development process through integration with code editors, allowing developers to navigate the code more efficiently and get more accurate hints and auto-completion, as well as enabling safe refactoring of large amounts of code.The Compiler is the heart of TypeScript, responsible for checking type correctness and transforming TypeScript code into JavaScript. However, to fully utilize TypeScript’s power, it’s important to configure the Compiler correctly. Each TypeScript project has one or more tsconfig.json files that hold all the configuration options for the Compiler.Configuring tsconfig is a crucial step in achieving optimal type safety and developer experience in your TypeScript projects. By taking the time to carefully consider all of the key factors involved, you can speed up the development process and ensure that your code is robust and error-free.The default configuration in tsconfig can cause developers to miss out on the majority of benefits of TypeScript. This is because it does not enable many powerful type checking capabilities. By “default” configuration, I mean a configuration where no type checking compiler options are set. For example:The absence of several key configuration options can result in lower code quality for two primary reasons. Firstly, TypeScript’s compiler may incorrectly handle null and undefined types in various cases. Secondly, the any type may appear uncontrollably in your codebase, leading to disabled type checking around this type.Fortunately, these issues are easy to fix by tweaking a few options in the configuration.Strict mode is an essential configuration option that provides stronger guarantees of program correctness by enabling a wide range of type checking behaviors. Enabling strict mode in the tsconfig file is a crucial step towards achieving maximum type safety and a better developer experience. It requires a little extra effort in configuring tsconfig, but it can go a long way in improving the quality of your project.The strict compiler option enables all of the strict mode family options, which include noImplicitAny, strictNullChecks, strictFunctionTypes, among others. These options can also be configured separately, but it's not recommended to turn off any of them. Let's look at examples to see why.The any type is a dangerous loophole in the static type system and using it disables all type checking rules. As a result, all benefits of TypeScript are lost: bugs are missed, code editor hints stop working properly, and so on. Using any is okay only in extreme cases or for prototyping needs. Despite our best efforts, the any type can sometimes sneak into a codebase implicitly.By default, the compiler forgives us a lot of errors in exchange for the appearance of any in a codebase. Specifically, TypeScript allows us to not specify the type of variables, even when the type cannot be inferred automatically. The problem is that we may accidentally forget to specify the type of a variable, for example, to a function argument. Instead of showing an error, TypeScript will automatically infer the type of the variable as any.Enabling the noImplicitAny compiler option will cause the compiler to highlight all places where the type of a variable is automatically inferred as any. In our example, TypeScript will prompt us to specify the type for the function argument.When we specify the type, TypeScript will quickly catch the error of passing a number to a string parameter. The return value of the function, stored in the variable res2, will also have the correct type.Configuring useUnknownInCatchVariables allows for safe handling of exceptions in try-catch blocks. By default, TypeScript assumes that the error type in a catch block is any, which allows us to do anything with the error. For example, we could pass the caught error as-is to a logging function that accepts an instance of Error.However, in reality, there are no guarantees about the type of error, and we can only determine its true type at runtime when the error occurs. If the logging function receives something that is not an Error, this will result in a runtime error.Therefore, the useUnknownInCatchVariables option switches the type of the error from any to unknown to remind us to check the type of the error before doing anything with it.Now, TypeScript will prompt us to check the type of the err variable before passing it to the logError function, resulting in more correct and safer code. Unfortunately, this option does not help with typing errors in promise.catch() functions or callback functions. But we will discuss ways to deal with any in such cases in the next article.Another option fixes the appearance of any in function calls via call and apply. This is a less common case than the first two, but it's still important to consider. By default, TypeScript does not check types in such constructions at all.For example, we can pass anything as an argument to a function, and in the end, we will always receive the any type.Enabling the strictBindCallApply option makes TypeScript smarter, so the return type will be correctly inferred as number. And when trying to pass an argument of the wrong type, TypeScript will point to the error.The next option that can help prevent the appearance of any in your project fixes the handling of the execution context in function calls. JavaScript's dynamic nature makes it difficult to statically determine the type of the context inside a function. By default, TypeScript uses the type any for the context in such cases and doesn't provide any warnings.Enabling the noImplicitThis compiler option will prompt us to explicitly specify the type of the context for a function. This way, in the example above, we can catch the error of accessing the function context instead of the name field of the Person class.Next several options that are included in the strict mode do not result in the any type appearing in the codebase. However, they make the behavior of the TS compiler stricter and allow for more errors to be found during development.The first such option fixes the handling of null and undefined in TypeScript. By default, TypeScript assumes that null and undefined are valid values for any type, which can result in unexpected runtime errors. Enabling the strictNullChecks compiler option forces the developer to explicitly handle cases where null and undefined can occur.For example, consider the following code:This code will compile without errors, but it may throw a runtime error if the user with name “Max” does not exist in the system, and users.find() returns undefined. To prevent this, we can enable strictNullChecks compiler option.Now, TypeScript will force us to explicitly handle the possibility of null or undefined being returned by users.find().By explicitly handling the possibility of null and undefiined, we can avoid runtime errors and ensure that our code is more robust and error-free.Enabling strictFunctionTypes makes TypeScript's compiler more intelligent. Prior to version 2.6, TypeScript did not check the contravariance of function arguments. This will lead to runtime errors if the function is called with an argument of the wrong type.For example, even if a function type is capable of handling both strings and numbers, we can assign a function to that type that can only handle strings. We can still pass a number to that function, but we will receive a runtime error.Fortunately, enabling the strictFunctionTypes option fixes this behavior, and the compiler can catch these errors at compile-time, showing us a detailed message of the type incompatibility in functions.Last but not least, the strictPropertyInitialization option enables checking of mandatory class property initialization for types that do not include undefined as a value.For example, in the following code, the developer forgot to initialize the email property. By default, TypeScript would not detect this error, and an issue could occur at runtime.However, when the strictPropertyInitialization option is enabled, TypeScript will highlight this problem for us.The noUncheckedIndexedAccess option is not a part of the strict mode, but it is another option that can help improve code quality in your project. It enables the checking of index access expressions to have a null or undefined return type, which can prevent runtime errors.Consider the following example, where we have an object for storing cached values. We then get the value for one of the keys. Of course, we have no guarantee that the value for the desired key actually exists in the cache. By default, TypeScript would assume that the value exists and has the type string. This can lead to a runtime error.Enabling the noUncheckedIndexedAccess option in TypeScript requires checking index access expressions for undefined return type, which can help us avoid runtime errors. This applies to accessing elements in an array as well.Based on the options discussed, it is highly recommended to enable the strict and noUncheckedIndexedAccess options in your project's tsconfig.json file for optimal type safety.If you have already enabled the strict option, you may consider removing the following options to avoid duplicating the strict: true option:It is also recommended to remove the following options that can weaken the type system or cause runtime errors:By carefully considering and configuring these options, you can achieve optimal type safety and a better developer experience in your TypeScript projects.TypeScript has come a long way in its evolution, constantly improving its compiler and type system. However, to maintain backwards compatibility, the TypeScript configuration has become more complex, with many options that can significantly affect the quality of type checking.By carefully considering and configuring these options, you can achieve optimal type safety and a better developer experience in your TypeScript projects. It is important to know which options to enable and remove from a project configuration. Understanding the consequences of disabling certain options will allow you to make informed decisions for each one.It is important to keep in mind that strict typing may have consequences. To effectively deal with the dynamic nature of JavaScript, you will need to have a good understanding of TypeScript beyond simply specifying “number” or “string” after a variable. You will need to be familiar with more complex constructs and the TypeScript-first ecosystem of libraries and tools to more effectively solve type-related issues that will arise.As a result, writing code may require a little more effort, but based on my experience, this effort is worth it for long-term projects.I hope you have learned something new from this article. Thanks for reading!Some rights reserved----Level Up CodingLead Frontend Engineer @Yandex | TypeScript | React | Meta-Frameworks | Dev Tools | Monorepo | Web PerformanceMaksim ZemskovinBetter Programming--1Julie Perilla GarciainLevel Up Coding--30Jacob BennettinLevel Up Coding--82Gabe A, M.Sc.inLevel Up Coding--2CihaninInteresting Coding--Love SharmainByteByteGo System Design Alliance--53Rico FritzscheinLevel Up Coding--25UX Movement--4Jacob BennettinLevel Up Coding--82Daley WilhelminUX Collective--74HelpStatusWritersBlogCareersPrivacyTermsAboutText to speechTeams



This post first appeared on VedVyas Articles, please read the originial post: here

Share the post

Unleashing the Power of TypeScript: Key Considerations in tsconfig

×

Subscribe to Vedvyas Articles

Get updates delivered right to your inbox!

Thank you for your subscription

×