A Static Sort of Typing

The more I use c#, the more I grow to enjoy having a type system.

I started with PHP- which I believe is dynamically typed, and Javascript, which is pretty much just the Wild West where anything goes.  I never really had to worry about providing info to my program about what this variable would be, or what might be returned from a function.  I remember my confusion in seeing the ‘void’ term for the first time on a function declaration.

And dynamic typing can be great.  It can be really quick and easy to set something up.  Example: to declare a variable in Python, you just type your var name then the value: i = 1.  There you go- i is ready to use and the language will infer (hopefully correctly) what you meant i to truly be.

But as a program becomes more complex, having static typing, or at least a static type checking system, becomes very useful. When I declare variable i in c#, it’s slightly longer: int i = 1, but that ‘int’ lets any program or action using it know that it is an integer.  With modern editors, you’ll be notified right away if you do something wrong with it.  At worst, you’re notified at compile time, not run time, so you can fix it before anyone notices that you tried to add the string ‘dozen eggs’ to the number 1 before calling .ToString().

And now in Javascript land, a small group of brave lawmen have come to town.  Typescript is keeping watch over our little project, and as someone who started out in dynamic/no type land, it seems like the best of both worlds.

Part of that is flexibility.  In most cases, using Typescript is optional.  Set it up in your JS project and don’t make any changes (except renaming .js to .ts so the transpiler finds what to work on).  Most times, your files will just work.  There are some exceptions, but it seems like most are due to really bad code (see personal example below).

I can still just declare a simple variable: const i = 1.  Or, I can provide more info: const i: number = 0.  In the latter case, the transpiler (and my editor) will complain if I try to add i to a string- they’re different types.  This flexibility allows for a smooth transition into Typescript- we can use type checking on just a few important functions or variables and leave some others as plain JS for now.  This is a very simple example: adding a string to a number in JS generally causes no problems, but things like this can be the source of very hard to find bugs (JS is well meaning in its type inference, but can’t always get it right).

One ‘gotcha’ I did run into was with a sorting function.  We needed to sort a grid by some options, but each column might have a different kind of data.  For example- the grid might have a column for date (a Date object), name (string), and id (number).  I tried running a simple array.sort method on all my info with a conditional on the type of what was passed:

return group.sort((a, b) => {
    if(typeof a[param] === 'number') {
        return b[param] - a[param];
    } else if(typeof a[param] === 'string') {
        return b[param] > a[param];
    } ...

a and b are objects and the param variable is passed into the wrapping function (which allows for sorting an array of objects by a specific parameter).

That’s a simplified version of the real first draft- the real one has checking for empty strings, conversions to lowercase to ensure we’re comparing the correct number code, etc.  However, there’s already a problem, according to Typescript (and any statically typed language).  There are two possible return types: number (branch one) and boolean (branch two).  This is fine (well, it’s allowed) in JS, but not in a statically typed language.  The Typescript transpiler throws an error and won’t cooperate.

And there is a quick and dirty solution.  Typescript has an ‘any’ type.  Add that as the return type for the sort function and it will transpile:

group.sort((a, b): any => {

But our sort function is still an ugly mess.  And that’s another thing static type checking seems to provide.  Initially, I was frustrated with the whole system- finding the ‘any’ type was very exciting.  But as I learn more c# (where you have to provide proper typing), I realize that the type system helps you write better code.  My old sort function was poorly written and hard to follow.  Having a function with multiple possible return types is not a great idea (I’m sure someone will tell me how wrong I am, but just go with it for now).  And in the sort function, this notion is absolutely correct.  With Javascript’s array.sort method, it seems generally best to return either 1 or -1 from each comparison.  You can just return the difference or true/false, but it can lead to bugs.  So, instead of the quick and dirty solution (putting the ‘any’ decorator on my function), I really needed to refactor the structure:

return group.sort((a, b) => {
    if(typeof a[param] === 'number') {
        return b[param] - a[param] > 0 ? 1 : -1;
    } else if(typeof a[param] === 'string') {
        return b[param] > a[param] ? 1 : -1;
    } ...

Please excuse any typos- this isn’t production code, just an example.  Each return checks for a boolean result, then returns either 1 or -1.  Now we have a function that uses the array.sort in a more efficient manner, and has a unified return type.  Typescript’s ‘any’ type is useful in some situations, but I now really check myself before using it.  Generally it’s a smell that means I’ve done something wrong or overly complex that can be refactored.

So, that was part of my journey to loving static typing.  It’s about delayed gratification.  More work up front for less headaches down the road.  By the way- a major side benefit of Typescript is that the transpiler will take car of any ES6 -> ES5, so you can use all the cool new JS features in addition to (optional) static typing.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s