cli  
Article Series

This article series discuss more than 30 different programming languages. Please read overview before you read any of the details.

Playing with Records Related Articles.

Where to Discuss?

Local Group

Preface

Goal: Continue Part One


5: Call Signatures Using Type Synonym

Type Reserved Word!

Writing a verbose typeful function could lead to a long line, and make your code unreadable.

const merge = (a: Array<string>, b: Array<string>): Array<string> => [...a, ...b];

We can solve this with type.

Simple Example

Consider this conventional function.

const func = function(a: number, b: number): number { return a+b; }

const z: number = func(6,7)
console.log (z)

We can rewrite using ES6’s fat arrow, with about the same result, as below code:

const func = (a: number, b: number): number => a+b;

const z: number = func(6,7)
console.log (z)

Or even better with some kind of function signatures, with about the same result, as below code:

type MyFunc = (a: number, b: number) => number;
const func: MyFunc = (a, b) => a + b;

const z: number = func(6,7)
console.log (z)

Typescript: Simple Example of Type Synonym as Function Signature

However, this is not a really a call signature. This type reserved word, is actually just a synonym.

The Songs Records

Before we apply to working example code. We need an example data, our legendary songs record:

interface Song{
  readonly title: string;
  readonly tags?: Array<string>;
}

const songs: Array<Song> = [
  { title: "Cantaloupe Island",
    tags : ["60s", "jazz"] },
  { title: "Let it Be",
    tags : ["60s", "rock"] },
  { title: "Knockin' on Heaven's Door",
    tags : ["70s", "rock"] },
  { title: "Emotion",
    tags : ["70s", "pop"] },
  { title: "The River" }
];

export { Song, songs };

Typescript: The Legendary Songs Record

We also need to export the interface.

export { Song, songs };

Example: The Mergable Type

Now it is time to apply what we know to a working example code.

import { Song, songs } from "./songs-data";

type Unique = (array: Array<string>) => Array<string>;

type Mergable = (
  array1: Array<string>,
  array2: Array<string>
) => Array<string>;

const
  unique      : Unique   = (a)    => [... new Set(a)],
  merge       : Mergable = (a, b) => [...a, ...b],
  mergeUnique : Mergable = (a,b)  => unique(merge(a, b));

let allTags: Array<string> = [];

songs.forEach(song => {
  if(song.tags) {
    allTags = mergeUnique(allTags, song.tags)
    console.log(allTags);
  }
});

The code above looks clean right? It is longer, but you can understand what’s going on, without a lot of mumbo jumbo.

More Functional Example

If you dare to embrace functional approach, we can do this with just ES2015 target.

import { Song, songs } from "./songs-data";

type GetTags = (array: Array<Song>) => Array<Array<string>>;
type Flatten = (array: Array<Array<string>>) => Array<string>;
type Unique  = (array: Array<string>) => Array<string>;

const
  getTags : GetTags  = (songs) => songs.map(song => song.tags || []),
  flatten : Flatten  = (array) => array.reduce((a,b) => a.concat(b)),
  unique  : Unique   = (array) => [... new Set(array)];

const allTags: Array<string> = unique(flatten(getTags(songs)));
console.log(allTags);

With the result about similar with below array:

$ ts-node 09-songs-flatten.ts
[ '60s', 'jazz', 'rock', '70s', 'pop' ]

The syntax is concise. Brief and Comprehensive.

Typescript: Call Signatures Using Type Synonym (Reserved Word)

No manual loop required. Just map iteration. This is simply math.

Function Chaining

How about chaining function? Consider have a look at this ES2019 target below:

import { Song, songs } from "./songs-data";

type   Unique  = (array: Array<string>) => Array<string>;
const  unique  : Unique = (array) => [... new Set(array)];

type  PickTags = (song: Song) => Array<string>;
const pickTags : PickTags = (song) => song.tags!

const allTags: Array<string> = unique(songs
  .filter(  pickTags )
  .flatMap( pickTags )
);
console.log(allTags );

Typescript: Chaining function

In order to use flatMap, do not forget to change the target, in tsconfig.json to ES2019.

{
  "compilerOptions": {
    "target": "ES2019",
    …
  },
  …
}

This typescript code should run well, with the right configuration.

Short Form

You can write Array<string> as string[]. Although personally this can lead to [string] typo. So be careful when you do this.

import { Song, songs } from "./songs-data";

type   Unique  = (array: string[]) => string[];
const  unique  : Unique = (array) => [... new Set(array)];

type  PickTags = (song: Song) => string[];
const pickTags : PickTags = (song) => song.tags!

const allTags: string[] = unique(songs
  .filter(  pickTags )
  .flatMap( pickTags )
);
console.log(allTags );

I don’t know if there is there is other thing, that I can do to improve this typescript code. I think I’d better move on to port, my other ecmascript to typescript, for learning purpose. And leave this simple script behind as just a memories of the past.


6: Using Deno

After playing around with ts-node, it makes sense to moved on to deno.

All the codes above works well, except we need an adjustment for export import.

Issue

This picture should be enough.

Typescript: Deno Export Interface Issue

Export Interface

Instead of ts-node style below:

interface Song{ … }
…
export { Song, songs };

We should use export reserved word as below:

export interface Song{ … }
…
export { songs };

Import

Now you can import as usual, except you must specify, the file extension .ts.

import { Song, songs } from "./songs-data.ts";

The script should works well. This is the only issue I face so far. And it has been solved already.

Bundle to Javascript

You can bundle typescript into javascript.

$ deno bundle 14-songs-flatmap.ts 14.js
Bundle file:///home/epsi/Documents/songs/deno/14-songs-flatmap.ts
Check file:///home/epsi/Documents/songs/deno/14-songs-flatmap.ts
Emit "14.js" (684B)

$ node 14.js
[ '60s', 'jazz', 'rock', '70s', 'pop' ]

Native Executable

You can even compile typescript.

$ deno compile 14-songs-flatmap.ts --unstable
Check file:///home/epsi/Documents/songs/deno/14-songs-flatmap.ts
Bundle file:///home/epsi/Documents/songs/deno/14-songs-flatmap.ts
Compile file:///home/epsi/Documents/songs/deno/14-songs-flatmap.ts
Emit 14-songs-flatmap

$ ./14-songs-flatmap
[ "60s", "jazz", "rock", "70s", "pop" ]

$ ls -lh | grep flatmap
-rwxrwxrwx 1 epsi epsi 34M Jan 10 01:04 14-songs-flatmap
-rw-r--r-- 1 epsi epsi 380 Dec 20 21:49 14-songs-flatmap.ts

Typescript: Deno Compile Size Issue

But beware of the size.


7: Generics Example

Consider different approach to solve unique value without using Set. This function should be available to find unique array for other type, instead of just string.

This algorithm require two function:

  1. exclude
  2. unique (called recursiverly)

This is just an example, and keep in mind, that recursive with javascript is computationally intensive.

An Algorithm Case

Why reinvent the wheel?

My intention is writing a custom pattern matching example, so later I can rewrite other algorithm based on this example. You can read the detail on the first article. The record overview.

Consider going back to simple data. We need to discuss about solving unique list.

Exclude Function

The exclude is simply a filter function with below details:

const exclude = (value: string,
        tags: Array<string>): Array<string> => {
  let newTags: Array<string> = []

  for (const tag of tags) {
    if (tag != value) newTags.push(tag)
   }

  return newTags
}

const tags: Array<string> =
  ["rock", "jazz", "rock", "pop", "pop"]

console.log(exclude("rock", tags))

With the result about similar with below array:

$ ts-node 21-tags-exclude.ts
[ 'jazz', 'pop', 'pop' ]

Recursive Unique Function

With exclude function above, we can build unique function recursively, as below code:

const exclude = (value: string,
        tags: Array<string>): Array<string> => {
  return tags.filter(tag => tag != value)
}

const unique = (tags: Array<string>)
             : Array<string> => {
  if (tags.length <= 1) {
    return tags
  } else {
	const [head, ...tail] = tags
    const newTails: Array<string> =
      unique(exclude(head, tail))

    return [head, ...newTails]
  }
}

const tags: Array<string> =
  ["rock", "jazz", "rock", "pop", "pop"]

console.log(unique(tags))

With the result about similar with below array:

$ ts-node 22-tags-unique.ts
[ 'rock', 'jazz', 'pop' ]

Both functions can be applied to any type, not just string, so we can apply generic.

Generic Unique Function

Consider to apply generics to unique function, as below code:

const unique = <T>(tags: T[]): T[] => {
  if (tags.length <= 1) {
    return tags
  } else {
	const [head, ...tail] = tags
    const newTails: T[] =
      unique(tail.filter(tag => tag != head))

    return [head, ...newTails]
  }
}

const tags: Array<string> =
  ["rock", "jazz", "rock", "pop", "pop"]

console.log(unique<string>(tags))

With the result about similar with below array:

$ ts-node 23-tags-generic.ts
[ 'rock', 'jazz', 'pop' ]

Typescript: Generics Function Type


Conclusion

I love singing

Once I step into this typescript. It doesn’t seems to be scary anymore. In fact this looks fun. I should play with language more often.

If only I had known about this, I would learn in a few years earlier. Maybe started programming since college, or even highschool days.

Nobody told me, that time. But you had me know. You know what to do. Just start learning new language. Don’t be scared.

What do you think?


What is Next 🤔?

A true functional programming language. Haskell as a mockup for purescript.

Consider continue reading [ Haskell - Playing with Records ].