Skip to content

Instantly share code, notes, and snippets.

@blemoine

blemoine/blog.md Secret

Created March 23, 2017 00:23
Show Gist options
  • Save blemoine/1b98f9973c2f84468c88ae641122b133 to your computer and use it in GitHub Desktop.
Save blemoine/1b98f9973c2f84468c88ae641122b133 to your computer and use it in GitHub Desktop.

Type checked dynamic calls in TypeScript

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.

Literal Types

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.

Using String Literal Types

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

Get a property dynamically

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

Type guards

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

Some shortcut syntax à la lodash

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.

Conclusion

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".

Side Note on Dependant Types

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment