All the code present in this article was tested with TypeScript 2.2.1 and Lodash 4.6.1
The emergence of static type checking in JavaScript has put an end to the dynamic programming approach. If you had the following snippet in your JavaScript
https://gist.github.com/82d01f27609d34d0c39a81a0a2dcf4df
for it to work in TypeScript, the only solution is to cast unknwonObject
to any
? Or does it? Spoiler: No, and this article will show you how to keep this kind of dynamic code without losing any type checking goodness.
A value can be of multiple types. For example:
https://gist.github.com/08d6efed0021684ebd4a7f949d509329
In the last line of this example, "foo"
is a literal type. It's a type that contains one and only one value and which has same the same name that this value. The type "foo"
contains the value "foo"
. Thus, this type is named a string literal type.
String literal types are more precise than string
- they can be seen as subtypes because they share the same structure. If we want to use it as parameters of function, we have to use generic programming and explicitly state this fact:
https://gist.github.com/1556781059b4f0a15c5882b240282a64
The type operator keyof
let you get the name of the attributes of an object . For example:
https://gist.github.com/2878ae6b3a254872ec2671b60617610b
With this operator, it's now possible to get property dynamically while staying typesafe.
https://gist.github.com/fc74855d88bedbd12855ed1460f6335d
We can go further by using type guards. This feature let you write a test (that will be executed at runtime) that will check that a variable is really of a specified type, and thus you don't have to cast this variable. An example could be:
https://gist.github.com/2dc489eee7b8d4dd65c57d918522a9c3
But we can do better with what we've seen previously and have some generic function that behave somewhat like the has
of lodash
but that is statically checked.
https://gist.github.com/6e5ac99e792526be5636df524bfa6591
Lodash offers the possibility to use some of it's function with shortcut syntax like:
https://gist.github.com/65d716c005ea11268495274541e6fd08
But with what we've seen previously, we can do better and write our own typesafe pluck:
https://gist.github.com/47e3e648ed54909ef52b6166a9fa5022
We can do that for the vast majority of callback shortcuts available in lodash, but this will be left as an exercise for the reader.
Now that we know how to get back some dynamic programming capability in TypeScript, should we use this? In my opinion, not everything should be used: has
is very useful, in particular when working with some legacy code in JavaScript. pluck
for example add complexity in the function signature for a very little gain in usability (writing a string instead of a one line function). So I would advise not to use it. Anyway, as always in software programming, there is no absolute response other than "use what make sense to you and your team".
You can see some kind of recuring pattern in the above examples: the return type of getProperty
and pluck
depends on the value of one of their parameters. So, can we say that TypeScript allows some kind of dependant typing? The straight answer is no. This confusion come from the fact that string literal types have the same name that their value, but do not be mistaken, these functions truly depends on types and not on values.