Category Archives: TypeScript

Websockets with JavaScript

Let’s create a JavaScript websocket server.

To start with carry out the following steps…

  • Create a folder, mine’s wsserver and cd to it
  • Run yarn init -y
  • Run tsc –init
  • Run yarn add ws @types/ws
  • Add a file (mine’s server.ts) for our server code
  • Add another file this time for a sample client (mine’s client.ts)
    • Now we will add the scripts, so add the following to package.json

      "scripts": {
        "server": "node server.js",
        "client": "node client.js"
        "build": "tsc"
      }
      

      Let’s add some code, in the server.js put the following

      import WebSocket from "ws";
      
      const wss = new WebSocket.Server({ port: 4000 });
      
      wss.on("connection", ws => {
        ws.on('message', message => {
          console.log('received: %s', message);
        });
      
        ws.on("close", () => {
          console.log("Close connection");
        });
      
        ws.send("Server says Hi");
      });
      

      In the above code we create a new websocket server on port 4000 then we handle any connection’s (once a connection is made the server sends back the message “Server says Hi”. The ws.on “message” will output any messages sent from the client. It should be fairly obvious that the “close” is called when a connection is closed.

      Let’s now put the following in the client.ts

      import WebSocket from "ws";
      
      const ws = new WebSocket("ws://localhost:4000");
      
      ws.onopen = () => {
        ws.send("Client says Hi");
      };
      
      ws.onerror = error => {
        console.log(error);
      }
      
      ws.onmessage = msg => {    
        console.log(`Client onmessage: ${msg.data}`);
      }
      
      ws.onclose = () => {
        console.log("Close");
      };
      

      In the above we open the connection to the web socket server, when the connection is open (onopen) we send a message “Client says Hi” to the server, obviously any errors are sent to the onerror function and any message from the server are routed to the onmessage function, finally onclose is called if the server closes the connection.

      Now run the script command yarn build and then in one terminal run yarn server and in another terminal run yarn client.

      We can also send specific commands to the server, for example in the client add the following to the onopen function

      ws.send("getData");
      

      Within the server add the following

      ws.on("getData", msg => {
        console.log("getData called")
      });
      

      So now when the server receives a getData messages it’s routed to this server function.

      If we have multiple client’s connecting to a server, we can send messages to each client using code, like the following

      wss.clients.forEach(client => {
        if (client.readyState === WebSocket.OPEN) {
          client.send("Broadcasting a  message);
        }
      });
      

      We can also extend the server “connection” function like this

      wss.on("connection", (ws, request) => {
        console.log(request);
      }
      

      The request parameter allows us to check the request.url if we want to change take different actions depending upon the query part of the websocket URL.

      It’s often useful to implement ping/pong capabilities which would allow us to check if the client still exists, here’s rather simplistic example of this type of code.

      wss.on("connection", (ws, request) => {
        ws.isAlive = true;
      
        ws.on("pong", () => {
          console.log("Pong called");
          ws.isAlive = true;
        });
      
        setInterval(function ping() {
          wss.clients.forEach(function each(ws: any) {
            if (ws.isAlive === false)  {
              console.log("Terminated client")
              return ws.terminate();
            }
              
            ws.isAlive = false;
            console.log("Ping client")
            ws.ping();
          });
        }, 10000);
      });
      

Be aware that an async (in TypeScript) when not required adds extra code

Whilst aysnc/await is not formally part of the ES spec (I believe it is available when targetting es2017) we need to be aware of situations where declaring async adds code which is not required.

Specifically I came across some code where a class’s method was marked as async but without an implementation, i.e.

class Derived {
    public async doSomething(): Promise<void> {
    }
}

This compiled/transpiled with the tsconfig.json settings of the project (a React project) and will produce the following code

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
class Derived {
    doSomething() {
        return __awaiter(this, void 0, void 0, function* () {
        });
    }
}

Obviously is not the intention here, i.e. to include the __awaiter code etc. What the code should have looked like is

class Derived {
    public dataBind(): Promise<void> {
        return Promise.resolve();
    }
}

which then produces JavaScript matching exactly this code, i.e.

"use strict";
class Derived {
    dataBind() {
        return Promise.resolve();
    }
}

I know this might seem a little picky, but from what I could see, for every file that includes an empty async method we get an __awaiter created, considering we use minifiers etc. to try to reduce our code size, this obviously makes a difference when code size is important.

JavaScript tagged templates

If you’ve seen code such as the one below (taken from https://www.styled-components.com/docs/basics)

styled.section`
  padding: 4em;
  background: papayawhip;
`

You might be interested in the styled.section code. This is a function and uses template literals as input via template literal syntax. In this usage its known as a tagged template or tagged template literals.

Let’s create our own function to show how this works.

function tt(literals: any, …substitutions: any) {
console.log(literals);
console.log(substitutions);
}

Note: I’m using TypeScript, hence the use of the any keyword, but just remove this for JavaScript code.

If we now run the following code

const name1 = "Scooby";
const name2 = "Doo";

tt`Hello ${name1} World ${name2}`

The following will be logged to the console

[ 'Hello ', ' World ', '' ]
[ 'Scooby', 'Doo' ]

The first values are an array of the literals passed to our function, the second are the substitutions.

Literals will always be an array of substitutions.length + 1 in length. Hence in the example above the literals contains an empty string item at the end to ensure this is the case.

Note: The last item in the literals array is an empty string but ofcourse if we had a string after the ${name2} then this would be the last item, hence to combine these two arrays into a resultant string would require us to ensure we merge all items.

We can therefore combine our two arrays to form a single result using a simple loop, like this


function tt(literals: any, ...substitutions: any) {
  let s = "";

  for (let i = 0; i < substitutions.length; i++) {
    s += literals[i] + substitutions[i];
  }

  return s + literals[literals.length - 1];
}

In the above we’re simply returning a string representing the merge of the two arrays. Remember literals.length will be substitutions.length + 1, hence we simply append that after looping through the smaller of the arrays.

Ofcourse this it not really that useful, if all we wanted to do was return a string we could just create a template literal. Let’s look at a couple of ways of enhancing the functionality.

The first obvious requirement is that we should be able to pass functions into the templates. For example if we have something like this

const t = tt`
 firstName: ${name1};
 lastName: ${name2};
 preferred: ${choice => (choice ? name1 : name2)};
 `;

The choice value needs to be supplied by the calling code and in this example code there’s no easy was to pass this data into t. So first off we need to wrap the tt function within another function and return it, like this

 
function tt(literals: any, ...substitutions: any) {
  return function(options: any) {
    let s = "";

    for (let i = 0; i < substitutions.length; i++) {
      s += literals[i];
      s += typeof substitutions[i] === "function"
        ? substitutions[i](options)
        : substitutions[i];
    }
    return s + literals[literals.length - 1];
  };
}

In the above we’ve also added changes to the original tt function to detect functions within the substitutions. If a function is found whilst looping then it’s invoked by passing in the supplied options.

This implementation then returns a function which, when invoked by passing in some value (in this case named options), will loop through the literals and substitutions and invoking any functions by forwarding the supplied options.

Hence we can call the new tt method like this, for example

t({choice: true});

This would return a string and would return

firstName: Scooby;
lastName: Doo;
preferred: Scooby;

So now for the next enhancement, let’s instead of returning a string, return an object – all we need to do is split on semi-colons to get key/value items where the key will become the object’s property and the value obviously the value stored within the property.

We’ll make a slight change to the code above to this

function tt(literals: any, ...substitutions: any) {
  return function(options: any) {
    let s = "";

    for (let i = 0; i < substitutions.length; i++) {
      s += literals[i];
      s += typeof substitutions[i] === "function"
        ? substitutions[i](options)
        : substitutions[i];
    }

    return toObject(s + literals[literals.length - 1]);
  };
}

The toObject function has been introduced and it’s purpose is to…

  • Take a string which is semi-colon deliminated for each key/value pair
  • Extract each key/value pair which should be deliminated with colons
  • For each entry we will create a property with the name taken from left of the colon on an object and the value right of the colon will be assigned to the property as a value

Here’s the code for toObject

const toObject = (value: any): any =>
  value
    .split(";")
    .map(entry => {
        const e = entry.split(":");
        if(e.length == 2) {
            const key = e[0].trim();
            const value = e[1].trim();
            return [key, value];
        }
        return undefined;
    })
    .filter(entry => entry != undefined)
    .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1]}), {});

This is not a complete solution as we’re not ensuring validity of the key as a property name. For example you’ll have noticed in styled.component or even React’s styles, that hyphen keys, i.e. background-color or similar would be converted or expected to be backgroundColor. So a simply change would be to convert line 7 to this following

const key = ensureValid(e[0].trim());

and now we introduce a new function to handle all our checks, for now we’ll just ensure the hyphen’s or dot’s are removed and replaced by camelCase

const ensureValid = (key: string): string => 
 key.replace(/[-.]+/g, c => c.length > 0 ? c.substr(1).toUpperCase() : '');

Obviously this function is quite limited, but you get the idea. It can then be used in the toObject function, i.e.

// change
const key = e[0].trim();
// to
const key = ensureValid(e[0].trim());

Taking things a little further

The code below is based upon what was discussed in this post, but extended a little, to start with here’s a more complete implementation of the above code

const ensureValid = (key: string): string => 
    key.replace( /[-.]+([a-z]|[0-9])|[-.]$/ig, (_match, character, pos) => {
        if(pos == 0) {
            return character.toLowerCase();
        }
        else if(character == null) {
            return '';
        }

        return character.toUpperCase();
    });

const toObject = (value: any): any =>
  value
    .split(";")
    .map(entry => {
        const e = entry.split(":");
        if(e.length == 2) {
            const key = ensureValid(e[0].trim());
            const value = e[1].trim();
            return [key, value];
        }
        return undefined;
    })
    .filter(entry => entry != undefined)
    .reduce((obj, entry) => ({ ...obj, [entry[0]]: entry[1]}), {});

function tt3(literals: any, ...substitutions: any) {
    return function(options: any) {
        let s = "";

        for (let i = 0; i < substitutions.length; i++) {
            s += literals[i];
            s += typeof substitutions[i] === "function"
                ? substitutions[i](options)
                : substitutions[i];
        }

        return toObject(s + literals[literals.length - 1]);
    };
}

const name1 = "Scooby";
const name2 = "Doo";

const t = tt3`
 -First-6name-: ${name1};
 last-Name: ${name2};
 preferred: ${options => (options.choice ? name1 : name2)};
 `;

console.log(t({choice: true}));

Now let’s have a bit of fun and refactor things to allow us to extract our object from alternate data representations. We’ll create an ini style way to define our objects

const camelCase = (key: string): string => 
    key.replace( /[-.]+([a-z]|[0-9])|[-.]$/ig, (_match, character, pos) => {
        if(pos == 0) {
            return character.toLowerCase();
        }
        else if(character == null) {
            return '';
        }

        return character.toUpperCase();
    });

type splitterFunc = (value: any) => [{key: any; value: any}|undefined];

const standardSplitter = (value: any):  [{key: any; value: any}|undefined] =>
    value
        .split(";")
        .map(entry => {
            const e = entry.split(":");
            if(e.length == 2) {
                const key = camelCase(e[0].trim());
                const value = e[1].trim();
                return [key, value];
            }
            return undefined;
        });

const iniSplitter = (value: any):  [{key: any; value: any}|undefined] =>
        value
            .split("\n")
            .map(entry => {
                const e = entry.split("=");
                if(e.length == 2) {
                    const key = camelCase(e[0].trim());
                    const value = e[1].trim();
                    return [key, value];
                }
                return undefined;
            });
    

const toObject = (value: any, splitter: splitterFunc = standardSplitter): any =>
    splitter(value)
      .filter(entry => entry != undefined)    
      .reduce((obj, entry) => ({ ...obj, [entry![0]]: entry![1]}), {});


function tt3(literals: any, ...substitutions: any) {
    return function(options: any, splitter: splitterFunc = standardSplitter) {
        let s = "";

        for (let i = 0; i < substitutions.length; i++) {
            s += literals[i];
            s += typeof substitutions[i] === "function"
                ? substitutions[i](options)
                : substitutions[i];
        }

        return toObject(s + literals[literals.length - 1], splitter);
    };
}

const name1 = "Scooby";
const name2 = "Doo";
    
const t = tt3`
 -First-6name-: ${name1};
 last-Name: ${name2};
 preferred: ${options => (options.choice ? name1 : name2)};
 `;

 const t1 = tt3`
 -First-6name- = ${name1}
 last-Name = ${name2}
 preferred = ${options => (options.choice ? name1 : name2)}
 `;

console.log(t1({choice: true}, iniSplitter));

Extension methods in TypeScript

Extension methods in C# are a great way to modularise functionality within a class in such a way (for example) to have a basic object with minimal methods and then extend this with further functionality that can be reference only if required.

Hence you might only have a need for the bare bones class in some cases and therefore only need to include that in your code base, alternatively you might also depend upon some advanced functionality that can be added when required. Another use case is adding functionality to third party libraries to extend their functionality.

Ofcourse we might simple extend/inherit from the class to add our new functionality but this ultimately mean’s we’re using a different type. With extension methods in C# we extend a String (for example) with extra functionality as opposed to created a subclass named something else, like ExtendedString.

So can we implement something similar to C#’s extension methods in TypeScript (and therefore JavaScript)? Yes we can, let’s look at a simple example, an Option class for handling defined/undefined values in a functional way. Here’s the Option.ts file

export class Option {
    value: any;

    constructor(value: any) {
        this.value = value;
    }

    isSome(): boolean {
        return this.value != null;  
    } 

    isNone(): boolean {
        return !this.isSome();
    }
}

Hence this is a bare bones implementation which we might extend further with further functionality. Let’s create a file for our extension methods, mine’s named OptionExtensions.ts, which might look something like this

import { Option } from './Option';

declare module './Option' {
    interface Option {
        ifElse(elseValue: any): any;
    }
}

Option.prototype.ifElse = function(elseValue: any): any {
    return this.isSome() ? this.value : elseValue;
}

In the above code we declare a module with the same name as the one which wish to extend and then declare an interface with our new methods. The interface in essences merges with the type to allow us to view our new methods as if they’re on the original Option type.

Finally we can start implementing our new functionality via the JavaScript prototype functionality.

In this example you can see we also have access to the this reference to allow our new functionality to hook into the Option fields etc.

Now let’s look at this in usage

import { Option } from "./Option"
import "./OptionExtensions";

const o = new Option(undefined);
console.log(o.ifElse(999));

That’s it, we pull in the extension methods via the import “./OptionExtensions”; when we want the extended functionality and we can call our extension methods as if they were written into the Option class itself.

TypeScript utility types

Whilst looking into the NonNullable<> type I noticed there’s a bunch of utility types. These types are used to construct other types.

I’m having trouble at this time understanding the use cases for some of these types, so will solely cover those that I can see use cases for.

Starting point

Let’s create a simple interface which we’ll start off with

interface Person {
    name: string;
    age: number;
}

Partial<T>

Use case

We might have a type T with one or more mandatory fields, Partial<T> takes a type T and produces a new type where all fields are optional, so using

type PartialPerson = Partial<Person>;

will create

interface PartialPerson {
    name?: string;
    age?: number;
}

Required<T>

Use case

The opposite to Partial<T> we may have a type with one or more optional fields and we want to produce a type with mandatory fields, so using

interface PartialPerson {
    name?: string;
    age?: number;
}

type RequiredPerson = Required<PartialPerson>

will create

interface RequiredPerson {
    name: string;
    age: number;
}

Readonly<T>

Use case

In some cases we might have a type T and wish to generate a new type where all those fields are marked as readonly, so using

type ReadonlyPerson = Readonly<Person>;

will create

interface ReadonlyPerson {
    readonly name: string;
    readonly age: number;
}

Record<K, T>

Use case

We might wish to generate a new type with fields of type T.

The Record<K, T> takes two types and produces a new type per value passed into the type parameter K of type parameter T, so for example

type RecordPerson = Record<'mother' | 'father', Person>;

will create

interface RecordPerson {
    mother: Person;
    father: Person;
}

Pick<T, K>

Use case

We might have a type T and wish to generate a new type made up of just selected fields.

The Pick<T, K> takes a type T and keys, K, as a union from T. The new type will then be made up of the fields declared in K, for example

type PickPerson = Pick<Person, 'name'>

will create

interface PickPerson {
    name: string;
}

ReturnType<T>

Use case

Useful in situations where we have a function and we want to get the type being returned by the function.

The ReturnType takes a type function T and returns the return type from the function, so let’s create the following code

function getPerson() : Person {
    return { name: "Scooby", age: 12 }
}

type ReturnsPerson = ReturnType<typeof getPerson>;

Getting started with Redux in React

Lot’s of Getting started posts at the moment, and probably a lot more to come. This one’s on using Redux with React and TypeScript.

Let’s create a sample application…

  • yarn create react-app {insert app name} –typescript
  • yarn add redux
  • yarn add react-redux
  • yarn add @types/react-redux
  • We can now delete the App.* files and the *.svg
  • Add folder components to src and also reducers
  • In src/components add Counter.tsx (we’re going to recreate the redux example component for in a tsx). Here’s the code
    import React, { Component } from 'react';
    
    interface CounterProps {
        value: number;
        onIncrement: () => void;
        onDecrement: () => void;
    }
    
    export default class Counter extends Component<CounterProps, {}> {
        constructor(props: CounterProps) {
            super(props);
            this.incrementAsync = this.incrementAsync.bind(this);
            this.incrementIfOdd = this.incrementIfOdd.bind(this);
        }
    
        incrementIfOdd() {
            if (this.props.value % 2 !== 0) {
              this.props.onIncrement()
            }
          }
        
        incrementAsync() {
          setTimeout(this.props.onIncrement, 1000)
        }
    
        render() {
            const { value, onIncrement, onDecrement } = this.props
            return (
              <p>
                Clicked: {value} times
                {' '}
                <button onClick={onIncrement}>
                  +
                </button>
                {' '}
                <button onClick={onDecrement}>
                  -
                </button>
                {' '}
                <button onClick={this.incrementIfOdd}>
                  Increment if odd
                </button>
                {' '}
                <button onClick={this.incrementAsync}>
                  Increment async
                </button>
              </p>
            );
        }
    }
    
  • Now in src/reducers add the file counterReducer.ts and put the following code into it
    export default (state: number = 0, action: any) => {
        switch (action.type) {
          case 'INCREMENT':
            return state + 1
          case 'DECREMENT':
            return state - 1
          default:
            return state
        }
    }
    
  • Finally, replace the contents of the index.tsx with the following
    import React from 'react';
    import ReactDOM from 'react-dom';
    import './index.css';
    import * as serviceWorker from './serviceWorker';
    import { Provider } from 'react-redux'
    import { createStore } from 'redux'
    import counter from './reducers';
    import Counter from './components/Counter';
    
    const store = createStore(counter);
    
    const render = () => {
        ReactDOM.render(
            <Provider store={store}>
                <Counter
                    value={store.getState() as number}
                    onIncrement={() => store.dispatch({ type: 'INCREMENT' })}
                    onDecrement={() => store.dispatch({ type: 'DECREMENT' })}
                />,
            </Provider>, 
            document.getElementById('root'));
    }
    
    render();
    store.subscribe(render);
    
    serviceWorker.unregister();
    
  • If everything is correct you should be able to execute yarn start and see the web page with +, – buttons etc. and clicking + or – will increment and decrement the displayed counter.

That’s a lot to take in, so what have we actually done?

Redux supplied a storage container for our application state. In the index.tsx file we create a store passing our reducer (src/reducers/counterReducer.ts) Reducers are called in response to the store.dispatch calls. In this case within index.tsx we dispatch the actions with the type set to strings INCREMENT and DECREMENT. The reducer receives these messages then makes state changes (although not actually changing the state directly but returning a new state).

As the Redux documentation on reducers states, “Remember that actions only describe what happened, but don’t describe how the application’s state changes”.

The next piece of code to look at is

store.subscribe(render);

We’ve wrapped the render code for the application in the render function. Subscribe then allows us to listen to messages on the redux store and calls the render function to render changes. The following part of the Counter code within the index.tsx file then simply assigns the current store state to the Counter value property

value={store.getState() as number

There’s not lot to really say about the Counter component which is standard React code for displaying buttons etc. and exposing properties as used in index.tsx.

More…

This is a simplistic example. Redux documentation states that it’s not advisable to write the store.subscribe code but instead use the connect function provided by React Redux for this functionality.

In this instance we create a src/containers folder and add the file CounterContainer.ts, here’s the code

import {  connect } from 'react-redux'
import Counter from './../components/Counter';

const mapStateToProps = (state: any) => {
    return {
        value: state as number
    }
}

const mapDispatchToProps = (dispatch: any) => {
    return {
        onIncrement: () => dispatch({ type: 'INCREMENT' }),
        onDecrement: () => dispatch({ type: 'DECREMENT' }),
    }
}

export const CounterLink = connect(
    mapStateToProps,
    mapDispatchToProps
)(Counter);

export default CounterLink;

Here we write code to map state to properties and dispatch to properties (if we don’t handle either of these we simply supply a null in place of the function in the connect function.

As you can probably see, in mapStateToProps, the state is supplied and we simply apply it to the value property (which is on our Counter). In mapDispatchToProps we link the onIncrement and onDecrement to the dispatch functions.

Finally in index.tsx replace the Counter component with our newly created and exported CounterLink, i.e. here the new index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import counterReducer from './reducers/counterReducer';
import CounterLink from './containers/CounterContainer';

const store = createStore(counterReducer);

ReactDOM.render(
    <Provider store={store}>
        <CounterLink />
    </Provider>, 
    document.getElementById('root')
);

serviceWorker.unregister();

TypeScript’s never type, what’s the point ?

At first the never type may seem a slightly odd, possibly even pointless type. It can be used to denote that a function never returns, such as an infinite loop or a function simply throws an Error, hence again, never returns. These use cases don’t seem that useful, but you get the idea. The never type denotes that something should never occur.

Where never becomes a lot more useful is in situations where something should never occur in your application’s control flow, specifically regarding choice operators such as switch statements and if..else when used for exhaustive checks.

Let’s look at an example of this…

You have an type Choice which is currently made up of a union of three values, which looks like this

type Choice = 'A' | 'B' | 'C';

Let’s now create a simple function which returns a string based upon the choice value

function makeChoice(choice: Choice) {
  switch(choice) {
    case 'A': return 'A selected'
    case 'B': return 'B selected'
    case 'C': return 'C selected'
  }
  // should never reach
}

makeChoice('C');

We’re handling all the possible values of the union and all is fine with the world.

TypeScript correctly transpiles the code and if we mistakenly replace the change makeChoice(‘C’) to makeChoice(‘D’) (not included in the union) TypeScript reports the error Argument of type ‘”D”‘ is not assignable to parameter of type ‘Choice’.

What happens is – if we had a default case or if the options within the switch were exhausted and the instruction pointer made it to the comment part of the function – which in this case should never occur (as all values in the union are handled). This is where the never type comes in once all options are exhausted the choice variable in essence becomes a type never. I know, it seems strange, but read on…

So, what if we add a new value to the Choice union, let’s say ‘D’, then we have a bit of a problem, TypeScript will transpile without error but our case statement is not handling the new value and hence this may get into production without warning.

Let’s make this a little more obvious by changing our code to this

function makeChoice(choice: Choice) {
  switch(choice) {
    case 'A': return 'A selected'
    case 'B': return 'B selected'
    case 'C': return 'C selected'
  }
  let c: never = choice;
}

Note: Assuming unused variables are not set as errors in your preferred linter then everything will compile and appear without error.

What’s happening here is that the transpiler knows that all choice options are exhausted, hence choice (if you like) changes to become of type never. Hence the line of code let c: never = choice; is valid as this line/instruction should never occur.

What happens it we add a new choice, so we now add ‘D’ to the Choice union and TypeScript will now report an error. This is because the choice variable may now have another value which is not handled by the switch statement and we’ll get the following error “Type ‘”D”‘ is not assignable to type ‘never'”. Which is good because now when we transpile time we’ll be alerted to a potential issue.

Prior to adding the let c: never = choice if we transpile the code to JavaScript we get the following code, which if we change ‘C’ to ‘D’ will not report any problem (which could be fine or could be bad depending upon our usage).

function makeChoice(choice) {
   switch (choice) {
      case 'A': return 'A selected';
      case 'B': return 'B selected';
      case 'C': return 'C selected';
   }
}
makeChoice('C');

So what we really want to do in our TypeScript file is throw an Error in place of the let c: never = choice, then this will catch non-exhaustive switch statements and will be transpiled into JavaScript to give us a runtime guard to highlight a potential issue.

Let’s create a simple function to handle this so our code now looks like this

function unreachable(param: never): never { 
   throw new Error('should not reach here')
}

function makeChoice(choice: Choice) {
  switch(choice) {
    case 'A': return 'A selected'
    case 'B': return 'B selected'
    case 'C': return 'C selected'
  }
  unreachable(choice);
}

which transpiles to almost exactly the same code.

As the function unreachable never returns, we mark it as such by using the never return type.

If we now try to pass ‘D’ to the function makeChoice in the JavaScript code, an exception will occur so we’re covered at runtime now as well as at tranpsile time.

Another example of using never is in the type NonNullable which is part of TypeScript.

type NonNullable<T> = T extends null | undefined ? never : T;

In this instance if the generic type T is null or undefined then never is returned, hence the following type will actually be of type never and this not assignable to

type A = NonNullable<null>;

Getting started with Storybook

Storybook allows us to prototype and test UI components in isolation from your application. We’re going to “get started” using Storybook with React, but it also supports Vue and Angular.

Let’s create the project and add required libraries.

Note, that the npx command should not be run from VSCode (or other Atom based editor by the sounds of it), I got an error EPERM: operation not permitted, unlink.

In the steps below we also install enzyme for test rendering. We’ll also add material-ui, just for the fun of it.

  • npx -p @storybook/cli sb init
  • yarn create react-app storybooksample –typescript
  • yarn add @types/storybook__react -D
  • yarn add @types/enzyme -D
  • yarn add enzyme -D
  • yarn add enzyme-adapter-react-16 -D
  • yarn add @types/enzyme-adapter-react-16 -D
  • yarn add @material-ui/core

The storybook “getting started” web page suggests we now run the following commands to check everything was installed correctly, so let’s do this, run

  • yarn test
  • yarn storybook

Let’s now remove the storybook generated code as we’ll replace this with our own code. So in the folder src/stories, delete index.js and add a file named setupTests.ts to the src folder, here’s the code for this file

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

Before we go too much further let’s create a sample component that will use to demonstrate testing via storybook. In the src folder add a folder named components/LogButton and in this create a file named LogButton.tsx – the name’s unimportant ofcourse, this is just a sample component which will be a new Button component, but hopefully will help demonstrate how we can use storybook.

In LogButton.tsx place the following code

import React from 'react';
import Button from '@material-ui/core/Button';

interface LogButtonProps {
    onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
}

export class LogButton extends React.Component<LogButtonProps, {}>{    
   render() {
      return (
         <div>
            <Button variant='contained' onClick={this.props.onClick}>Log</Button>
         </div>
      );
   }
}

Let’s now create a standard unit test for this component, this is not required for storyboard, but it’s good practise. In the same src/components/LogButton folder add the file LogButton.test.tsx and here’s a very simple test to got into this file

import React from 'react';
import { mount } from "enzyme";
import { LogButton } from "./LogButton";

test('Loading component should not throw error', () => {
    const logButton = mount(<LogButton />);
    expect(logButton.exists()).toBe(true);
});

This will just check that the component, when loaded, loads successfully. We can now run yarn test to verify this code works.

Now let’s get storybook up and running with our component.

In the .storybook folder, replace the config.js code with the following

import { configure } from '@storybook/react';

const req = require.context('../src', true, /.stories.(ts|tsx|js)$/)
const loadStories = () => req.keys().forEach(filename => req(filename));
configure(loadStories, module)

This will automatically load stories based upon the filename/extensions .stories.

Alongside LogButton.tsx and LogButton.test.tsx, add LogButton.stories.tsx. This will supply the code required to integrate into storybook and also allow us to write code to allow us to test the UI component via storybook.

import React from 'react';
import { storiesOf } from '@storybook/react';
import { LogButton } from './LogButton';
import { action } from '@storybook/addon-actions';

storiesOf('LogButton', module)
    .add("Log", () => <LogButton onClick={action('clicked')} />);

Now run yarn storybook and the storybook server and UI should display along with our LogButton now being the only component available. Selecting the “Log” story, when the LogButton is clicked the action will display the text “clicked”.

So what we’ve done is create a very simply component based upon a Button which we also declared some properties – well in this case we’ve created a single property, an onClick event. The story created for the button then hooks into the button’s click event and when used via storybook allows us to test the control in isolation via storybook’s UI. This is not a unit test or automated test so much as an interactive UI test where, as developers, we can verify our functionality. Let’s say the Button’s text changed when clicked, now we could start interacting with the button via storybook and confirm everything works as expected.

There’s a lot more to storyboard than the above, but this is a good starting point.

Typescript interfaces

Interfaces (within Typescript) are used in a variety of ways.

Defining expectations/restrictions

We can define an interface such as IPoint

interface IPoint {
    x: number;
    y: number;
}

Just like other languages, we can then implement this interface and we’re required to duplicate the properties or methods declared on it.

For example here’s an implementation

class Point implements IPoint {
    constructor(public x: number, public y: number) {        
    }
}

We’ve used public constructor parameters hence implementing the IPoint interface.

Now we can create an instance of the Point like this

// p is a Point
var p = new Point(2, 3);
// p is declared as an IPoint
var p: IPoint = new Point(2, 3);

Within TypeScript an interface can also simply be thought of as shaping our data, so in this example we could create an anonymous class of type IPoint like this

var p: IPoint = {x : 2, y: 4};

We can also declare an instance of an anonymous type like this

var p = {x : 2, y: 4};

Typescript supports “duck typing” so we can create functions such as

function output(p: IPoint) {
   //
}

and we can pass a type which implements an IPoint or a duck typed anonymous type, for example

output({x : 2, y: 4});

Because of duck typing we do have an issue whereby the following two interfaces are structurally equivalent

interface IPoint {
    x: number;
    y: number;
}

interface I2d {
    x: number;
    y: number;
}

and hence this will compile and run

var i2d: I2d = {x : 2, y: 4};
var p: IPoint = i2d;

In such a case, the interfaces have the same properties and names and are structurally equivalent.

Things get a little more interesting with interfaces and anonymous types, in that we can write something like this

function whatIsThis() {
    return {x:2};
}

Obviously it’s not an IPoint or I2d, but it could be. In this example it’d create an anonymous type but we could cast the type like this, but this will fail to compile due to the missing y property.

function whatIsThis() {
    return <IPoint>{x:2};
}

Empty interfaces

We can also define empty interfaces, such as

interface IEmpty {}

function output(e: IEmpty) {
    console.log(e);
}

output("Hello World");

In this case this is equivalent to an any and hence does not cause a compile time error and output will display “Hello World”.

Type erasure

Interfaces within Typescript are erased at compile/transpile time, hence whilst they aid in ensuring our types are as expected, once compiled to JavaScript they’re removed.

Hence no runtime type checking exists for such types.

TypeScript constructor parameter properties

TypeScript offers a short-cut to creating properties/fields from the parameters declared on the constructor.

For example, if we declare our class and constructor like this

class Person {
    constructor(name: string, age: number) {
    }
}

let p = new Person("Scooby", 10);
p.name = "Doo";

The TypeScript transpiler will display the error “Property ‘name’ does not exist on type ‘Person'” and obviously the parameters name and age will not exist within the Person class as they’ve not been declared.

However if we prefix the parameters with either public, private, protected or readonly then TypeScript generates properties on the Person object automatically for us.

protected parameter properties

As you’d probably expect, with the accessor of protected properties are generated which are visible to the Person object and any subclass of the Person.

For example

class Person {
    constructor(protected name: string, protected age: number) {
    }
}

When we run this through the transpiler we get the following

var Person = /** @class */ (function () {
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    return Person;
}());

If we attempt to access the properties name and age from outside the class (using TypeScript) then we’ll get the error “Property ‘name’ is protected and only accessible within class ‘Person’ and its subclasses.”.

private parameter properties

If we now change the accessors to private, for example

class Person {
    constructor(private name: string, private age: number) {
    }
}

The transpiler will, again, create the same output as the previous JavaScript code, but the generated properties, from the TypeScript point of view, are only accessible from the Person class. Trying to access them from outside of the Person class will result in the following error, “Property ‘name’ is private and only accessible within class ‘Person’..

public parameter properties

Changing the accessors to public will, as you probably expected, create public properties/fields which are accessible outside of the Person class, here’s the altered source code.

class Person {
    constructor(public name: string, public age: number) {
    }
}

Ofcourse, the JavaScript code is unchanged.

readonly parameter properties

Finally, if we now change the accessors to readonly, for example

class Person {
    constructor(readonly name: string, readonly age: number) {
    }
}

The transpiler will generate, what appears to be, getters only. Hence trying to interact with these properties outside of the class will result in the following error “Cannot assign to ‘name’ because it is a read-only property.”

Whilst JavaScript can support the concept of readonly properties, the transpiler does not go this route (shown below)

Readonly properties in JavaScript

If we take the code generated by the transpiler, we could add the following

Object.defineProperty(Person.prototype, "name", {
    value: "name",
    writable: false
});

and when run (assuming we try to assign a value to name), we’ll get the following error “Cannot assign to read only property ‘name’ of object ‘#‘”.