The problem with TypeScript and its practices
Tags: javascript, typescript, webdev, frontend
Published: 2023-03-16 21:45:04

Most of you probably believe TypeScript is best practices these days. It has some advantages, but also disadvantages. Here are some myths and problems with it.

## Myth 1: It is typed and safe.
TypeScript is either typed nor safe. Being a typed language means the compiler 100% know the type every single value, the binary representation of the value in memory and how to access it. The typescript transpiler/compiler cannot and does not know this information. The dynamic nature of JavaScript/ECMAScript prevent it. What TypeScript actually do is try to figure that information out or let you specify it, but it has no way to actually knowing.

```
const value: number = randomInt();
//  value can be anything, really!
```


## Myth 2: It create less bugs
Contradictory what many people say, TypeScript do not create less bugs compared to applications written in JavaScript. It's not my opinion, its [research](https://www.researchgate.net/publication/359389871_To_Type_or_Not_to_Type_A_Systematic_Comparison_of_the_Software_Quality_of_JavaScript_and_TypeScript_Applications_on_GitHub). The research study checked the 15% most popular applications on github. The study in a nutshell says the following:

- The use of "any" has a positive impact on bug resolution time.
- TypeScript code contains equal or more bugs than JavaScript code.
- Its take longer time to fix bugs in projects that is written in TypeScript.

So you should definitely not feel bad if you use "any" or a loose mode in TypeScript.

It is also important to understand that, even if you may find TypeScript code more readable, does it not mean it actually is more readable. Readable code is by definition simple to change and understand, so if it takes longer to fix various bugs in a programming language than in another, is it a sign something is wrong in your understanding what readable code actually is.

PS. I know it exists other studies that say the opposite, but as noted in the research paper as well, those studies are either focus only on a few projects or library code. This is different than what most of us do in our daily life. **Most of us code applications, not libraries.**


## Myth 3: Scalability
How well your application scale regarding code-complexity have nothing to do whatever you code in JavaScript or TypeScript. It is just adversating from Microsoft or a TypeScript lover if someone tell you that. To be honest, types is the least important language feature and even calling it a feature is controversial. Even research papers in 1970s noted it.

Have you heard of loose coupling? It is most of the time the factor that will decide regarding your application will scale or not. It comes in many favors and some people use different words, but the meaning is more or less the same: The less the programmer need to know, the better.


## Myth 4: Future proof
TypeScript is not in any way future proof.  In every places you can run TypeScript today, do you actually run JavaScript. There is a [proposal](https://github.com/tc39/proposal-type-annotations) to add some type-annotations to the language, but if you read all issues and even meeting notes is it clear:

- Annotations will just be treated as comments. You cannot trust it the type in any way.
- Most TypeScript code will never work because it uses TypeScript-specific features.
- It does not offer any technical benefits.
- Many people are against the proposal, some of those people are inside the committee itself.

Do you remember HTTP 2 push? Chrome [deprecated](https://developer.chrome.com/blog/removing-push/) the support because too few websites used it. So even if it got standardized (that is a huge "if"), would browsers probably not add support for it anyway:

- It does not offer any technical benefits, more the opposite (more bytes => slow website).
- Almost every website use bundlers and and those who does not will almost certain use TypeScript specific features that is not supported anyway.


## Problem 1: Encourage named exports
Almost every module should export only one thing. There is very few exceptions to this, for example configuration files or a file containing multiple constants. And if you export only one thing, the default export is the obvious candidate. The argument TypeScript lovers usually say is it ease refactoring but it is technically impossible. 

If you use default exports do you hide the identifier/name of the thing you export. It is by definition better because it remove a dependency, you do not need to know what name of some thing has within a file, only the interface of the thing the file exports. It's great. It means less coupling and less "need to know". Its honor SOLID principles and is great software design. It also encourage the developer to give great names for imported modules and each file has different contexts, so it make clear sense different names/identifiers may be used depending on context. 

The issue is of course and it is the main reason why some developers prefer named exports, it force the developer to give each package a name when you import it, so different files may use different names:

File 1
```
import Foo from 'somewhere';
```


File 2
```
import Bar from 'somewhere';
```

The consequence is that if you use some "refactoring" tools, will it be harder to rename the "default export", especially on a project-wide basis. Both file 1 & 2 will probably still use the names Foo and Bar even after a automatic refactoring for example. And it is great because there is hopefully a good reason why those names were used in the first place. Some people forget that.


## Problem 2: Do not support import by .ts extension
ECMAScript/JavaScript import modules by import/dependency specifiers and every plattform I know will convert the dependency specifier to some path or an url it can fetch. If the direct location cannot easily be defined, must the platform perform some kind of traversal (visit many files before it "knowns"). This process is slow, but remarkable slow if it is done over a network. This can be fixed if the developer provide more specific dependency specifiers, for example adding the file-extension. But there is a problem:
TypeScript do not support if you add the .ts extension. It does not [rename dependency specifiers](https://github.com/microsoft/TypeScript/issues/27481). Its extremely weird actually:

- The TypeScript team do 100% know TypeScript is not supported natively anywhere in the world. So you cannot evaluate a file containing TypeScript code. It must first be converted to JavaScript.
- The TypeScript team 100% know the ".ts" extension is their own file-extension and it is extremely likely if someone want to import a ".ts" file from a TypeScript file, is the file very likely a TypeScript file.
- The TypeScript transpiler itself will re-write all code, have almost in every case access to all dependencies and will create ".js" files by default.

There is no excuse for not supporting it.

## Problem 3: Encourage bloat
The TypeScript community encourage developers to some really bad habits that make code bases bloated. Examples:

### Over-use strict mode.
Strict mode do not produce less bugs nor it is more readable. Sure, you may believe so, but science says it's not. You should absolutely use "any" if it makes the code shorter and easy to read, yet there is an insane belief its bad. Its not! 

### Overuse of unions types
If your function has multiple declarations, use multiple functions. There is a reason why parseFloat and parseInt is different functions instead of just "parseNumber".

### Overuse of types
You should not care about the type a specific value has, but the interface the value has. Instead of doing:

```
function getName(user: User): string {
    return user.name;
}
```
should you prefer:
```
const getName = ({ name = '' } = {}) => name;

getName()  // OK
getName(123)  // OK
getName(true)  // OK
getName(undefined)  // OK
getName(Symbol('test')) // OK
getName(null) // TypeError, but this is the only case
```
The same applies if you work with generic and variadic arguments:

```
const add = (...args) => args.reduce(((s, v) => s + v), args.shift());
```
The code style is called defensive coding and it is scientifically proven to be the best method among programming languages in general together with tests to actually decrease the number of bugs and create more robust software. It a very important skill to learn. And yes TypeScript will detect if you call "getName" with something else than an object. If it does not, check your tsconfig.


Disclaimer
----------
I know there is a lot of people in the TypeScript community that is so insecure in their programming skill so they take any critic against the programming language personal. Please do not. I don´t want to force you stop using TypeScript. Use what every programming you want. I just want to spread some facts that I know are unpopular, but yet undeniable true.