Context
TypeScript is presented, by the authors, as “a strongly typed programming language”.
For anyone who has worked with other strongly typed languages, like Java, Kotlin, C#, this normally means that types are checked before runtime, and guaranteed, unless the users explicitely tries something dangerous like casting.
In TypeScript however, there are several ways of ending, without being warned, with completely wrong types at runtime.
This article presents one. There are more, which will be the subjects of more articles in the near future.
The issue with any
There are a few ways to break the type system in TypeScript, but for ńow, I’m focussing on the fact that any
can be implicitely casted into anything else.
No-one in their right mind would, on purpose and for anything other than a throw-away script, write something like this:
const double = (value: any) => {
return 2 * value
}
It doesn’t however, need to be that basic.
Examples
A couple of example to illustrate slightly less obvious cases that can go un-noticed.
JSON.parse
JSON.parse
is a built-in function that returns any
:
type MyType = {
key: string;
}
const parsed: MyType = JSON.parse('{"value": "key"}')
// parsed is actually { value: string }
There are libraries that do things like generating JSON schema, validating an input, and inferring a type, but out of the box, any
is what you get.
Array(n).fill("value")
Array(n)
returns an array of n
undefined values, typed any[]
. fill(value)
fills the array with the given value, without changing its type.
const array: string[] = Array(5).fill(42);
// array is actually a number[]
What about unknown
?
TypeScript has another type that is used when the specific type is not known: unknown
. It is equivalent to Java’s Object
. And it requires an explicit cast to be assigned to another type:
const value: unknown = 42;
const casted: string = value as string;
// This cast is necessary
Why does it matter
This confuses people (e.g. this question on StackOverflow). There are a few lint directive to restrict the usage of any
, but it is still fairly easy to miss one.
Once any
is somewhere, the error will only show up at runtime, making the whole point of a typed system moot.
To be honest, I don’t fully understand why we need to have any
in typescript, and why unknown
is not sufficient.
Next time: how indexed types lie about what they return.