Categories
Typescript Terrors Uncategorised

Typescript Overloading

I spent a couple of hours recently trying to solve a problem with overloading in TypeScript only to realise there wasn’t actually a problem at all – I had just completely misunderstood how overloading works !

Unlike other languages where an overload acts as an “alias” for the implementing method, in TypeScript an overload “replaces” / hides the implementing method – the implementing method becomes inaccessible unless called via an overload signature.

Example

I’ll try to show a basic example and then go into more details.

Imagine, for the sake of this example, an equivalent of “parseInt” (that we could call doParseInt) that takes either a number or a string.

  • If a number is passed we return the number directly.
  • If a string is passed however, a second argument “radix” is required.

We could code this like:

// Basic function to test overloading: can be called in two ways
// value is number (radix not used)
// value is string (radix required)

function doParseInt(value: (number | string), radix?: number): number {
  if (typeof value === 'number') {
    return value;
  }
  if (typeof value === 'string') {
    return parseInt(value, radix);
  }
  throw new Error(`unexpected value: ${value}`);
}

We can use it like:

const val1 = doParseInt(123); // OK
const val2 = doParseInt('123'); // Error - radix is required if value is string
const val3 = doParseInt(123, 8); // Error - radix is not used if value is number
const val4 = doParseInt('123', 10); // OK
const val5 = doParseInt(123 as (number | string)); // OK

This works but is not great from a type-safety point of view – we have no way of forcing to people to pass a radix if value is string, or likewise from not passing a radix if value is numeric.

Overloading to the rescue – We add our overload signatures to refine the way we can call the implementing function:

function doParseInt(value: number): number;
function doParseInt(value: string, radix: number): number;

Note these are not “functions” – they do not have a body!

They serve purely as “overload signatures” – method signatures that refine (limit) how we can call the implementing method.

After adding our signatures, everything seems great except “val5” which no longer compiles – it appears the fact of adding an overload signature has made the original implementing method inaccessible !

const val1 = doParseInt(123); // OK
// const val2 = doParseInt('123'); // No longer compiles - great
// const val3 = doParseInt(123, 8); // Likewise, great
const val4 = doParseInt('123', 10); // OK
const val5 = doParseInt(123 as (number | string)); // No longer compiles either .... !

Results in:

error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'.
Type 'string' is not assignable to type 'number'.

The problem comes from val5 – we want to be able to call directly the non-overloaded implementation method.

However, this is not possible in TypeScript – adding a single overload makes the non-overloaded implementation inaccessible.

To resolve this, we need to simply add the original method signature as an overload signature of itself.

The final code looks like:

function doParseInt(value: number): number;

function doParseInt(value: string, radix: number): number;

function doParseInt(value: (number | string), radix?: number): number;

// Basic function to test overloading: can be called in two ways
// value is number (radix not used)
// value is string (radix required)
function doParseInt(value: (number | string), radix?: number): number {
  if (typeof value === 'number') {
    return value;
  }
  if (typeof value === 'string') {
    return parseInt(value, radix);
  }
  throw new Error(`unexpected value: ${value}`);
}

In hindsight it seems clearly logical – we add overload signatures to refine/specialise the call, and so it doesn’t make much sense to leave the original implementing method available.

What would have been great would have been an error message more explicit: Implementing function not available if overload signature exists” for example

This example is slightly contrived: The actual problem was with array signatures (RxJS combineLatest for example) but that will be the subject of my next post.

Categories
Fitness

Fitness 09/05

Started off the morning with two classes: Body Pump and RPM.

Body Pump 113 (45 mins, lunges + shoulders)

  • Squats – 7.5kg x2 with the bar, 10kg for the presses at the end (no change)
  • Chest – 15kg x2 with the bar, 6kg x2 with the dumb-bells (no change)
  • Back – 7.5kg x2 with the bar (no change)
  • Triceps / Biceps – 6kg x2 with dumb-bells for the biceps (no change)
  • Lunges / Shoulders – 10kg for the presses (no change)

Spin 86 (30 mins)

Categories
Fitness Sports

Fitness 09/01

Spin (30 mins)

It’s currently the end the holiday season in France at the moment, so this week my gym is running “video sessions” – no instructor, but we follow the class on the TV.

BodyPump 113 (45mins)

I also participated in the evening BodyPump class – edition 113.

  • Squats – 7.5kg x2 with the bar, 10kg for the presses at the end
  • Chest – 15kg x2 with the bar, 6kg x2 with the dumb-bells
  • Back – 7.5kg x2 with the bar – This song is an absolute killer on the forearms !
  • Triceps / Biceps – 6kg x2 with dumb-bells for the biceps
  • Lunges / Shoulders – 10kg for the presses
Categories
Git

Quick & Dirty Git Mirroring

A situation that happens often – you’re working on a repository (GitHub for example) also want your commits automatically mirrored to anther repository.

The obvious solution is to add a second remote, but that means having to constantly remember to push to both remotes.
After playing around with the idea of aliases and hooks, I fell upon a little-known Git feature – secondary fetch and push URLs.

We can add additional fetch and push URLs for a remote by using the reite set-url
For example, to add https://my-backup-remote as a remote for the current
git remote set-url –add –push origin https://my-backup-remote

Taking a peek at the .config fileL

[remote “origin”]
url = https://github.com/alanapz/snorlax.git
fetch = +refs/heads/*:refs/remotes/origin/*
pushurl = https://github.com/alanapz/snorlax.git
pushurl = \\\\192.168.1.40\\public\\projects\\snorlax
And

C:\dev\adista\snorlax>git remote show origin
* remote origin
Fetch URL: https://github.com/alanapz/snorlax.git
Push URL: https://github.com/alanapz/snorlax.git
Push URL: \\192.168.1.40\public\projects\snorlax
HEAD branch: master
Remote branch:
master tracked
Local ref configured for ‘git push’:
master pushes to master (up to date)

C:\dev\adista\snorlax>git push origin head -v
Pushing to https://github.com/alanapz/snorlax.git
To https://github.com/alanapz/snorlax.git
= [up to date] head -> master
updating local tracking ref ‘refs/remotes/origin/master’
Everything up-to-date
Pushing to \\192.168.1.40\public\projects\snorlax
To \\192.168.1.40\public\projects\snorlax
= [up to date] head -> master
updating local tracking ref ‘refs/remotes/origin/master’
Everything up-to-date

Notice that fetches are not affected – we fetch from only the fetch URL (perfect – it doesn’t really make sense to fetch from our backup remote).

C:\dev\adista\snorlax>git fetch -v
From https://github.com/alanapz/snorlax
 = [up to date]      master     -> origin/master

Quick, easy & dirty !

Categories
Code Quality

Snorlax – SonarQube reporting tool

My latest project is a basic SonarQube reporting tool, used to generate e-mail reports on unassigned and open issues by user and project.

Snorlax is designed do to two things:

  • Notify users periodically of all “overdue” issues (an overdue issue is one that is unresolved since a certain time).
  • Provide managers with a summary report of which users have the most overdue issues, and which projects have the most unassigned issues.

To Run

The easiest way is via Docker for Linux:

docker run -it
        -e SNORLAX_SONAR_URL=*SonarUrl*
        -e SNORLAX_SONAR_TOKEN=*ApiToken*
        -e SNORLAX_SMTP_SERVER=*SmtpServer*
docker.io/alanmpinder/snorlax:1.0

See README.md for a list of all supported environment variables.

Categories
WordPress

Error: WordPress could not establish a secure connection

So as you can see, I have recently re-setup my blog.

Everything seemed to go smoothly up until I tried installing a theme (either directly or via file-upload), whereupon I would receive the same error message every time:

Error: WordPress could not establish a secure connection to WordPress.org

I wasted a couple of hours upgrading PHP, CURL, OpenSSL as well as my the OpenSSL root before stumbling upon https://wordpress.org/support/topic/error-wordpress-could-not-establish-a-secure-connection-to-wordpress-org/

This user had exactly the same problem, which he traced to an incompatibility between Curl and SSL with regards to IPV6.
Following his advice, I added just before the end of __construct in wp-includes/Requests/Transport/cURL.php the following line:

curl_setopt($this->handle, CURLOPT_RESOLVE, array("api.wordpress.org:80:198.143.164.251", "api.wordpress.org:443:198.143.164.251"));

It’s an absolute terrible hack (hard coded IP addresses what could possibly go wrong!) but at least I can install themes on this blog now. So many thanks PeterBB, and eagerly awaiting a resolution to https://meta.trac.wordpress.org/ticket/3090

Categories
Uncategorised

Hello world!

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!