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)
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 };
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.
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 );
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.
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
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:
- exclude
- 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' ]
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 ].