My First Day With TypeScript

Okay, day-and-a-bit. First impressions!

I’ve been coding up a dice roller for a friend’s in-development RPG, and I decided on a whim to give TypeScript a try. Here’s some early impressions of the language — both TS and JS — coming from a mainly python background.

Interfaces

My very first thought was “what the heck do you need an Interface for?”. It seemed kinda weird to spell out the shape of an object before you actually use it- my python roots on show. After getting used to it, it seems like a good way of giving a clue as to how an object might be used, and putting that up-front makes you think a bit more carefully about the design early on when you might still be in the ‘transitioning from notes on paper/board to code’ stage.

Objects

Speaking of objects, JavaScript objects (and so too TypeScript objects) handle a bit different than python objects. In python, everything is an object is a phrase you’ll oftentimes hear; but the work I’ve done in python hasn’t really brushed up against things-as-objects. But compare the example image I included in the previous post I referred to back in the first paragraph:

When I first coded up the output, I instead got

Rolling 4 object Object
{ total: 24, dice: [ 7, 8, 2,7 ]}

Or something to that effect.

Printable Object Representations

Turns out I am quite used to python’s convenience functions __repr__ and __str__ being applied automagically; or at least knowing where to look to add that in. By comparison the equivalent in TS/JS seemed to be to provide an override for [util.inspect.custom], which also involved installing another package via npm and modifying my tsconfig.json. Chalk that one up to lack of familiarity with the ecosystem. I guess the equivalent in python is pip installing a package to provide a feature.

String Templates Work Slightly Differently

I then couldn’t get the printable string representation to print in a string template:

console.log(`Rolling ${diceCount} ${diceType}`);
// didn't work
console.log("Rolling", diceCount, diceType);
// works just fine

I asked on the TypeScript Gitter chat (where I got some very helpful replies and advice) about it and the template way of doing resolves things in a different order, so my util.inspect.custom is never called.

Implementation Differences

As part of that discussion someone else chimed in with “hang on, is this in the browser or in Node?”. I guess there are implementation differences, different features between Node and the browser, and presumably even between browser JS engines. Never mind between different EMCAScript versions! That said, for my purposes I probably won’t stumble across too many differences.

Array Comparisons

Or should I say “!%^& Array comparisons”:

Why, why WHY doesn’t an empty array equal another empty array? Even using the more lax of the comparators?! Have I gone mad?

Python is more sensible:

JS seems to handle other ’empty’ type comparisons fine:

It’s probably down to Array’s being a type of Object:

But then I’m not sure why an empty object doesn’t equal another empty object. There’s probably a great didactic opportunity there on objects, their representation and how they’re handled under-the-hood.

Spoiler: comparators work fine on primitives (things like strings, numbers etc), but on non-primitives like objects, arrays etc they compare references, rather than checking for equality.

Constructors Are Aren’t Mandatory

When writing a class, tsc (the compiler, for fellow newcomers) would complain at me if I didn’t have a constructor() method in my class, even an empty one. I therefore figured “hey, constructors must be necessary” and left an empty one in.

Except they’re not:

A class may contain at most one constructor declaration. If a class contains no constructor declaration, an automatic constructor is provided, as described in section 8.3.3.

(from the TS spec, section 8.3)

The compiler wanted a “constructor, method, accessor, or property”, but my util.inspect.custom implementation (see above) wasn’t one of those. Rearranging the order of methods in the class sorted that, though it still feels like something is off.

Interfaces and Types Are Definitions, Nothing More

For convenience, I wanted to create an ’empty’ object based on an Interface I had declared. Something like Interface Foo { bar: string, baz: number }; let quux = new Foo;. But to borrow from Morbo: INTERFACES DO NOT WORK THAT WAY!

Consider:

interface Person {                                                                                                  
        name: string;                                                                                               
        profession: string;                                                                                         
}                                                                                                                   
                                                                                                                    
let protagonist: Person = { name: "Rincewind", profession: "Wizzard" };

This compiles and works just fine. So why can’t you use Person as a ‘blank template’, with blank strings for when the name and profession are filled in by prompt/fetched from a database/etc?

The above example compiles down to:

var protagonist = { name: "Rincewind", profession: "Wizzard" };                                                     

So while using an Interface as an ‘object prototype’ of sorts would be lovely in a “Do What I Mean” kinda way, it’s there to define object shapes for the compiler.

Documentation in Comments Works Slightly Differently

In python I’m used to using triple-quoted docstrings to describe classes, functions, and the like. TS has its own convention, now formalised in the form of TSDoc. This is similar to JSDoc. Not a huge difference, just a slightly different way of writing.


Is there a conclusion to any of this? Probably not. I’ve only really scratched the surface of TypeScript. It and JavaScript seem to heavily favour callbacks, which I use less frequently (or perhaps differently) in python. The tooling is different. But despite a few frustrations — I’m looking at you, Array comparisons — along the way I am still in the honeymoon phase of using TypeScript. Perhaps once the module is published I’ll revisit this and see what I like, and what I like less.

Tell us what's on your mind