Is it okay to use generics as typecast in TypeScript?
On the Typescript Discord server, I came across the following response template:

Since I don't think there are all points in favor of casting at the call site, let me argue the advantages of both approaches:
Advantages of casting at the call site
1. Easy debugging
If an error occurs at runtime because you made a mistake with some type cast, it is straightforward to identify all instances of type assertions in the code. You just need to look at all the places where you used the keyword "as".
However, if you use type arguments for casting, you'll have a harder time differentiating it from genuine usages (like the useRef mentioned in the initial image).
2. Clearer intent
As user @Retsam19 pointed out on Discord:
A lot of people see code likeget<User[]>("/users")and think that TS is going to inject code that makes sure thatgetreturnsUser[]. (Because other languages often can change runtime behavior based on these kind of parameters). Or on the flip side they thinkget<User[]>is just another casting syntax.
Advantages of casting with a type argument
1. Guided Casting
The Typescript HandBook explains the following about how `as` works:
TypeScript only allows type assertions which convert to a more specific or less specific version of a type. This rule prevents “impossible” coercions like:const x = "hello" as number;
The phrase `less specific` is important here, because sometimes you just want to typecast to a more specific type that is very common in practice. For example, in the Lexical text editor you can do this:
1// You usually do this2const rowNode0 = tableNode.getFirstChild();3// ^? const rowNode0: LexicalNode | undefined45// But in some cases you know what type of node you are accessing:6const rowNode1 = tableNode.getFirstChild<TableRowNode>();7// ^? const rowNode1: TableRowNode | undefined89// Of course, you can do the same with an assertion:10const rowNode2 = tableNode.getFirstChild() as TableRowNode | undefined;1112// The problem is that the user could forget to handle13// the undefined case, and typescript would not complain:14const rowNode3 = tableNode.getFirstChild() as TableRowNode;
It's easy to get assertions wrong, so sometimes it's good to have a framework to avoid making even more insecure assertions than usual.
Also, if the implementation of getFirstChild changes, typescript might warn of an error, whereas using as the compiler would likely overlook it without raising any warnings
2. Less verbose
As you can see in the example above, <TableRowNode> is shorter than as TableRowNode | undefined. Also, if the returnType is wrapped in a complex generic like Something<T>, users must import the Something type every time they want to assert the function's return.
1// you need to import type Something2getSomething() as Something<TypeX>3// no need to import type Something4getSomething<TypeX>();
Some might consider this not an advantage, but a disadvantage. The same user goes on to say:
making unsafety more convenient is not a goal of mine. The fact that not using generics-as-typecast makes more friction is a benefit, not a drawback.
So, is it a good idea to use generics as typecast?
I have found a clear preference among the experts I spoke to not to use generics in this way.
Perhaps the fact that TypeScript still doesn't allow using type arguments in getters is a sign that the TS team feels the same way? Who knows.
Personally, I'm not sure and have mixed feelings. I see valid points in both approaches.
What do you think? Is it okay to use generics as typecast in TypeScript? Let me know!