What is a JSON feed? Learn more

JSON Feed Viewer

Browse through the showcased feeds, or enter a feed URL below.

Now supporting RSS and Atom feeds thanks to Andrew Chilton's feed2json.org service

CURRENT FEED

Joe Haines

Software developer from the UK

XML


Why I don't like Typescript

Permalink - Posted on 2019-03-03 00:00

Typescript is unarguably a very popular language. According to GitHub's “State of the Octoverse” it was the 3rd fastest growing language of 2018 and StackOverflow ranks it 12th in terms of the “Most Popular Technologies” in their 2018 developer survey.

In this post I'm going to put forward my case for Why I Don't Like Typescript.

Before I start I want to make it clear that this is my opinion. You might disagree and that's fine! Some of the things in this post are subjective because different people have different experiences and expectations so something that bothers me might not bother you. If you like using Typescript then you should keep using it, all I'd encourage you to do is checkout some of the other options as you might like them more.

Its type inference is poor at best

Type inference means that a programming language can detect the type of a variable without the programmer explicitly stating it. Some languages do this better than others but Typescript disappointed me with how poor its inference is, especially for a relatively new language.

Let's look at an example:

function one(name, age) {
    return two(name, age)
}

function two(name, age) {
    return age + name.length
}

export default one

This module (rather pointlessly) will add a given age to the length of the given name. We know from the export statement that the function two is effectively private — only one can call it because it's not exported or stored globally. That means that type hinting two is entirely pointless if one is type hinted because calling one is the only way to call two so we don't get any extra safety from typing both functions. However Typescript requires you to add types to both one and two as it can't seem to infer what the name and age parameters passed to two are, even though they have been passed directly by one.

function one(name: string, age: number): number {
    return two(name, age)
}

function two(name: string, age: number): number {
    return age + name.length
}

export default one

This doesn't seem like a big deal in this single example, but across a large code base this leads to huge amounts of pointless type annotations. If you've never used a language with a Hindley–Milner type system then you might not realise how much nicer it can be when the compiler does most of the hard work of determining types for you.

Unsafe type system

Typescript's type system is inherently unsafe — they admit as much in the official handbook:

TypeScript’s type system allows certain operations that can't be known at compile-time to be safe

Whether this is OK or not depends on what you think the goal of a language like Typescript should be. If you want to promote type safety in JavaScript then this decision makes sense — it's much easier to convert existing JavaScript code to Typescript by allowing common patterns that are unsafe. If, however, you think the goal of a typed compile-to-JS language should be to allow you to write safe programs then you might want to look elsewhere.

Typescript's type system also has another problem; it's way too easy to ignore. What I mean by this are the “escape hatches” built into the language, such as the any type and type assertions.

The any type is widely recognised as a potential problem, but it's worth highlighting how using it is incredibly unsafe and how the “noImplicitAny” configuration option isn't enabled by default. Given that you can enable this option easily and it's fairly widely known, I don't think this is a major problem with Typescript.

Type assertions, on the other hand, completely defeats the point of a type system. If you're unfamiliar, a type assertions allows you to mark a variable as any type you like, without having to prove that to the compiler. For example:

interface RemoteData {
    property1: string,
    property2: number
}

fetch('https://example.com')
    .then(response => response.json())
    .then(data => <RemoteData> data)

Here we've declared an interface with two typed properties and made a fetch call where we are able to declare data to be of the type RemoteData without having to prove it to the compiler. Typescript places some limitations on this — if you have a number and assert that it's a string Typescript won't let you. However AJAX requests are some of the most dangerous places in a code base as the result is always unknowable until the response is available.

Allowing you to mark a JSON payload as any type you like without having to prove it to the compiler opens a massive, dangerous hole in a code base. While a best practice would always be to validate the response and manually convert it to the correct type, any sufficiently large code base will inevitably end up with undesirable code without any intentional maliciousness.

Community type definitions

One of the main things pushing Typescript's usage is the DefinitelyTyped project and other community led type definitions for open source libraries.

The problem with these is that there's nothing to prove that the types are correct. All they give you is a false sense of security because the type definition comes from someone who didn't write the original code, may lag behind new releases or be outright wrong. A type definition that's incorrect can lead to runtime errors that can't be caught by the Typescript compiler because it trusts a third party type definition to be absolutely correct.

Without much better inference and a Typescript runtime to check for type errors during a program's execution, there's not a lot that can be improved here, but the current situation is untenable to me.

In order to have a code base that's protected from these kinds of errors, you need a really good unit test suite to help ensure all of the typings are correct. This is fine, but if you're going to ensure type safety through an incredibly thorough test suite then does Typescript add anything?

What's the alternative?

Typescript does what it sets out to do pretty well — it's a compile-to-JavaScript language that looks and feels a lot like JavaScript which massively reduces the barrier to entry for front end developers. What it doesn't do that well is provide a type system that ensures type safety (as much as a type system can).

Languages like Elm and Purescript provide type systems that are safer than Typescript's — Elm boasts “no runtime exceptions” as one of its main features. However this comes with a cost. Both languages require a lot more learning than Typescript does and they follow a paradigm that is likely to be unfamiliar to many JavaScript developers.

Personally I would always chose Elm over Typescript but for a company that decision isn't as easy. Elm's community is much smaller and breaking changes between releases are common (though releases are relatively infrequent), so it might not be as attractive as a language that's backed by Microsoft and a massive community.

It all depends whether you think the trade-offs are worth it.


Autodux

Permalink - Posted on 2018-04-10 00:00

Autodux is a library, written by Eric Elliott, to help automate Redux boilerplate.

Autodux lets you create everything you need for a Redux app in a handful of lines of code:

const {
  reducer,
  actions,
  selectors
} = autodux({
  initial: {
    username: 'Anonymous',
    email: 'anonymous@example.com'
  }
})

In this single call to autodux, you get a Redux reducer and an action and selector for each key in the initial state object.

Reducer

An autodux reducer is just a standard Redux reducer that's automatically setup to handle autodux actions. It's used like any other Redux reducer:

const { reducer } = autodux({ … })

const store = createStore(reducer)

Actions

A call to autodux returns an actions object which contains a function for each key in the initial state. For example, using the initial state from the above example, we would get setters for username and email inside the actions object:

{
  setUsername: Function,
  setEmail: Function
}

When one of these is called, it behaves like any standard Redux action creator, e.g.

actions.setUsername('abcd')

→ {
→   type: '/setUsername',
→   payload: 'abcd'
→ }

Custom actions

As well as the autogenerated actions that autodux creates for you, you can define custom actions with whatever logic you like. For example, to update both username and email at once, we can define a custom action setBoth:

const {
  reducer,
  actions,
  selectors
} = autodux({
  initial: {
    username: 'Anonymous',
    email: 'anonymous@example.com'
  },
  actions: {
    setBoth: (state, payload) => ({
      ...state,
      username: payload.username,
      email: payload.email
    })
  }
})

These actions will be automatically integrated into the autodux reducer and are called like any other action creator:

actions.setBoth({
  username: 'Admin',
  email: 'admin@example.com'
})

→ {
→   type: '/setBoth',
→   payload: {
→     username: 'Admin',
→     email: 'admin@example.com'
→   }
→ }

When passed to Redux's dispatch function, setBoth will update both the username and email properties of the Redux state:

store.getState()

→ {
→   username: 'Anonymous',
→   email: 'anonymous@example.com'
→ }

store.dispatch(
  actions.setBoth({
    username: 'Admin',
    email: 'admin@example.com'
  })
)

store.getState()

→ {
→   username: 'Admin',
→   email: 'admin@example.com'
→ }

Selectors

A call to autodux also returns a selectors object which, like actions, contains a function for each key in the initial state. These functions are selectors, which means they are functions for retrieving specific parts of the state tree. For example, using the initial state from the above example, we would get selectors for username and email:

selectors.getUsername(state)

→ 'abcd'

selectors.getEmail(state)

→ 'anonymous@example.com'

Custom selectors

Similarly to custom actions, custom selectors can be created too. For example, to select both username and email at once, we can define a custom getBoth selector:

const {
  reducer,
  actions,
  selectors
} = autodux({
  initial: {
    username: 'Anonymous',
    email: 'anonymous@example.com'
  },
  selectors: {
    getBoth: state => ({
      username: state.username,
      email: state.email
    })
  }
})

When called with the Redux state, getBoth will return an object with both the username and email properties from the Redux state:

const state = store.getState()

→ {
→   username: 'Anonymous',
→   email: 'anonymous@example.com'
→ }

selectors.getBoth(state)

→ {
→   username: 'Anonymous',
→   email: 'anonymous@example.com'
→ }

Autodux in action

As an example of converting a Redux app to use autodux, I've created an example Redux app with a commit converting it to an autodux app. Most of the existing code stays the same, with the majority of changes being a simplification of the reducer and action creator boilerplate.


Decorators

Permalink - Posted on 2018-02-25 00:00

A decorator is a function or class that can extend the capabilities of another function or class without inheriting from it. It allows new code to add or alter behaviour while the existing code remains unchanged.

In JavaScript (and much of the functional world) decorators will usually be functions:

const shouty = string => string + '!'
const extraShouty = string => string.toUpperCase()
const sayHi = string => 'Hi ' + string

console.log(
  shouty(
    extraShouty(
      sayHi('Bob')
    )
  )
)

// 'HI BOB!'

All of these functions accept and return the same type (a String in this case) so they can be used independently, or in any combination. Additional functions can be added to the chain without having to alter any of the existing ones.

In PHP (and much of the OOP world) decorators are usually classes, which means they will also usually implement the same interface as the classes they are decorating.

In my Flowder library I use decorators to allow maximum flexibility when configuring fixture loading. For example, there is a PhpFileLoader which can load data from a PHP file. To extend this to deal with directories there is also a DirectoryLoader class, which takes any class implementing LoaderInterface and calls its load method for every file inside a given directory.

In order to load a directory of fixture files, a PhpFileLoader and DirectoryLoader are composed together:

<?php

$loader = new DirectoryLoader(
    new PhpFileLoader()
);

Implementing the DirectoryLoader is as easy as accepting a loader in its constructor…

<?php

public function __construct(LoaderInterface $loader)
{
    $this->loader = $loader;
}

…and calling its load method when appropriate, inside its own load method:

<?php

public function load($directory)
{
    foreach (glob($directory . '/*') as $file) {
        foreach ($this->loader->load($file) as $table => $data) {
            yield $table => $data;
        }
    }
}

Given a project of enough size, loading a directory full of files repeated may become very slow. To combat this, there is also a CachingLoader class that caches the result of another loader's load method and returns it for any other calls to load.

We can add this to our previous loader configuration…

<?php

$loader = new CachingLoader(
    new DirectoryLoader(
        new PhpFileLoader()
    )
);

…and now we have a loader that will read all PHP files in a directory, cache the result of it and return that cached value for all other requests to load the data.

Many more examples in many more languages can be found on Wikipedia.

Decorators can be used in many situations instead of inheritance, which helps to reduce complexity in large code bases. It can also enable new functionality to be attached to legacy features without needing to edit the existing code, managing risk in hard to modify codebases.