Typescript: Playing with Interface
Tags: typescript, deno, functional
Published: 2020-12-21 13:08:51

This post was originally posted on my personal blog 😀. The source code example also provided in github, given in that blog.

🕷 [Typescript - Small Step into Typed](https://epsi.bitbucket.io/lambda/2020/11/03/playing-with-records-typescript-01/)

## Goal

> Goal: A small step into typescript using custom song script example.

I make this case example, because I want to learn typescript. The task is simply to collect unique tags from records.

-- -- --

## Type Basic

Consider start from simple. This is a conventional function in `typescript`:

```typescript
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:

```typescript
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:

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

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

You can spot the detail. This looks like `type signature` in `functional programming`.

Now let's get down to a record case example.

-- -- --

## Data Structure: Original in Javascript

Consider a case example of some popular songs from the old decades.

With `javascript`, I can just write away the records in below form:

```javascript
const songs  = [
  { 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 default songs;
```

-- -- --

## Data Structure: Ported to Typescript

With `Typescript`, you can peacefully append additional interface signature.

```typescript
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 };
```

![ Data Structure: Ported to Typescript](https://dev-to-uploads.s3.amazonaws.com/i/q62ovpr1a29f2cpuobbj.png)

-- -- --

## Procedural: in Javascript

In the old glorious days of `Javascript`, common approach to solve unique array in records is, by using loop.

```javascript
let tagSet = new Set();

// using set feature to collect tag names
songs.forEach(function(song) {
  if( "tags" in song ) {
    let tags = song.tags;
    console.log(tags);

    for (const tag of tags) {
      tagSet.add(tag);
    }
  }
});

console.log(tagSet);

// normalize to array
let alltags = [...tagSet];

console.log(alltags);
```

Well, not so old, this is already using `ecmascript 2015`.

-- -- --

## Functional: in Javascript

These days with `ecmascript 2019` we can use `flatMap`, so the code can be shorter.

```javascript
import songs from "./songs-data.js";

const unique = array => [... new Set(array)];

const allTags = unique(songs
  .filter(song => song.tags)
  .flatMap(song => song.tags)
);
console.log(allTags );
```

![Functional: in Javascript](https://dev-to-uploads.s3.amazonaws.com/i/8uduputxl8o72i44ypxd.png)

-- -- --

## Type Interface: in Typescript

With the right code, it is fun to type the interface signature.

```typescript
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 );
```

![Type Interface: in Typescript](https://dev-to-uploads.s3.amazonaws.com/i/g7xan834qu7ba1vblluo.png)

There are details to achieve this in provided link above.
I just want this notes to be short. So I strip out the details here.

-- -- --

## Type Interface: with Deno (also Typescript)

However, beware of the difference between `ts-node` and `deno`.

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

This picture should be enough to show the issue

![Deno Issue: Type Interface](https://dev-to-uploads.s3.amazonaws.com/i/xdpqahfhqlwkbhip2w8z.png)

### Export Interface

Instead of `ts-node` style below:

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

We should use `export` reserved word as below:

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

### Import

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

```typescript
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.

-- -- --

## Conclusion

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.

What do you think?