Category Archives: TypeScript

Destructing in JavaScript

In JavaScript/TypeScript, if you’re using the Prefer destructuring from arrays and objects (prefer-destructuring) eslint rule, you’ll want to use destructing syntax to get values from objects and arrays.

If we imagine we have an object like this

class Person
{
   firstName: string;
   lastName: string;
}

The to get the firstName from a Person instance, we tend to use

const firstName = person.firstName;

Instead this rule prefers that we use the following syntax

const { firstName } = person;

If for some reason (for example in React if you’re destructing state which may have been changed) you have need to get the value using destructing syntax but assigned to a new variable/value name, then we use

const { firstName: fname } = person;

Adding TypeScript to Electron

So we’ve seen that Electron is basically a browser window with integrations which allows us to use JavaScript to interact with it, but as somebody who prefers the type safety features that come with TypeScript, obviously I’d want to integrate TypeScript as well.

If you’ve not got TypeScript installed globally then run

npm install --save-dev typescript

If we take our application from the Getting Started post, lets simply started by adding a tsconfig, just run the following from your project’s root folder

tsc --init

Now change our main.js to main.ts. We’ll obviously need a build step to transpile the TypeScript to JavaScript which can then be uses via Electron, so add the following to the scripts section in package.json

"build": "tsc"

you might also like to either rename the start script or add another script to both build/transpile and run the application, i.e.

"go": "tsc && electron ."

Obviously this will litter your code base with generated .js files, so it’s best to transpile our code to a folder of it’s own, in this case we’ll call it src. Just add the following to the tsconfig.json

"outDir": "./src",

Then change package.json “main” to the following

"main": "./src/main.js",

That’s all there is to it, now we can add some type checking to our code and write TypeScript.

TypeScript 3.7.2

TypeScript 3.7.2 has just been released.

First off you’re going to want to install it globally on your machine, hence run (obviously this will install the latest version so not specific to version 3.7.2)

npm install -g typescript

or if you want it locally to your project, ofcourse you can run

npm install -D typescript 

If you’re using VS Code and you want to set it up for this version (if it’s not already set for the latest) then press F1 and select Preferences: Open User Settings adding (or editing) the following (off of the root level of the JSON)

"typescript.tsdk": "node_modules\\typescript\\lib",

I’m not going go through the new features exception to say we’ve now got optional chaining the ?. operator from C# and Nullish coalescing using the ?? operator.

Properties and fields in TypeScript

There’s several ways to handle properties within TypeScript, let’s look at a simple class

class Point {
    x: number;
    y: number;
}

Whilst Visual Code etc. will say these are properties, they’re more like public fields (if you wish to compare to a language such as C#), hence missing the functional side that comes with properties.

By default no accessors means the properties x and y are public. TypeScript allows us to mark them as private in which case we could then write functional getters and setters as per Java, for example

class Point {
    private x: number;
    private y: number;

    getX() {
        return this.x;
    }
    setX(x: number) {
        this.x = x;
    }
    getY() {
        return this.y;
    }
    setY(y: number) {
        this.y = y;
    }
}

TypeScript also supports C# style property getter and setters like this

class Point {
    private x: number;
    private y: number;

    get X() : number {
        return this.x;
    }
    set X(x : number) {
        this.x = x;
    }
    get Y() : number {
        return this.y;
    }
    set Y(y : number) {
        this.y = y;
    }
}

and like C# these get/set methods result in property style syntax, i.e.

var p = new Point();
p.Y = 4;
console.log(p.Y);

Constructors within TypeScript can reduce the ceremony for creating fields and properties by using the private or public keywords for constructor arguments, for example

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

// becomes

class Point {
    get x() {
        return this.x;
    }
    set x(x) {
        this.x = x;
    }
    get y() {
        return this.y;
    }
    set y(y) {
        this.y = y;
    }
}

Using private constructor arguments is equivalent private fields, so for example

class Point {
  constructor(private x: number, private y: number) {
  }
}

// becomes

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

If we need to overwrite the getter/setters functionality, we can write

class Point {
    constructor(public x: number, public y: number) {
    }
   
    public get x() : number {
        return this.x;
    }
    public set x(x : number) {
        this.x = x;
    }   
    public get y() : number {
        return this.x;
    }
    public set y(y : number) {
        this.y = y;
    }
}

One log decorator to rule them all

One log to rule them all

In a previous post we looked at implementing log decorators using the experimental features of TypeScript.

Obviously it’d be far nicer if we had a single log decorator that we can apply to each place where a decorator might be used, i.e. a log decorator which can be used instead of logClass, logMethod etc. We can simply create a log function which takes any number of arguments and have this delegate to the specific log function as required (a factory function basically). I’m not going to write the whole thing here, but something along the lines of (the following code) would do the job

function log(...args: any[]): void {
  switch(args.length) {
    case 1: 
      // return logClass
    case 2: 
      // return logProperty     
    case 3: 
      return (typeof args[2] === "number") ? 
        logParameter :
        logMethod
      default:
         throw new Error();    
   }
}

inversify

I wanted to use an IoC pattern/library in a project I was working on (a node server application where I would slot in the specific implementations of the data and services at runtime).

I cam across inversify, there may be other IoC’s for TypeScript, but this is the one I looked into and worked a treat for me.

yarn add inversify reflect-metadata

You will need to enable experimentalDecorators and emitDecoratorMetadata within the tsconfig.json file.

"experimentalDecorators": true,        
"emitDecoratorMetadata": true, 

as per the invertsify documentation, we should also have the following tsconfig.json properties set

"target": "es5",
"lib": ["es6"],
"types": ["reflect-metadata"],
"module": "commonjs",
"moduleResolution": "node",

As is usual in C# (at least), the best way to work with IoC is to define an interface for our abstraction and then an implementation. However for inverisfy we also define a Symbol for the interfaces. So let’s assume we’re going to have a Service interface along with RestService and WebsocketService.

First create your Service.ts file and here’s a simple example

interface Service {
  call(data: string): void;
};

export default Service;

Now let’s create a couple of implementations, RestService.ts

import "reflect-metadata";
import Service from "./Service";
import { injectable } from "inversify";

@injectable()
class RestService implements Service {
  call(data: string): void {
    console.log("RestService called");
  }
}

export default RestService;

As you can see, we decorate the class with @injectable as this class may be injected into another class.

Here’s our WebsocketService.ts

import "reflect-metadata";
import Service from "./Service";
import { injectable } from "inversify";

@injectable()
class WebsocketService implements Service {
  call(data: string): void {
    console.log("WebsocketService called");
  }
}

export default WebsocketService;

Within the types.ts (below) we create the symbols (keys/identifiers) for use with our types.

const Types = {
  Service: Symbol.for("Service"),
  Application: Symbol.for("Application")
};

export default Types;

Here’s an Application interface Application.ts

interface Application {   
  run(): void;
}

export default Application;

MyApplication.ts

import "reflect-metadata";
import { inject, injectable } from "inversify";
import Application from "./Application";
import Types from "./types";
import Service from "./Service";

@injectable()
class MyApplication implements Application {
  private readonly service: Service;

  constructor(@inject(Types.Service) service) {
    this.service = service;
  }

  run(): void {        
    this.service.call("");
  }
}

export default MyApplication; 

In the above you can see we’re injecting (via the @inject decorator on the constructor) a type of symbol type Service. Hence this is where the server implementation will be injected into.

To supply inversify with the implementations for various types, we create the file inversify.config.ts. In the example file below we bind the symbol type/identifier with an implementation.

import { Container } from "inversify";
import Service from "./Service";
import RestService from "./RestService";
import Types from "./types";
import WebsocketService from "./WebsocketService";
import Application from "./Application";
import MyApplication from "./MyApplication";

const container = new Container();

//container.bind<Service>(Types.Service).to(RestService);
container.bind<Service>(Types.Service).to(WebsocketService);
container.bind<Application>(Types.Application).to(MyApplication);

export default container;

Finally, here’s an example implementation of the index.ts

import container from "./inversify.config";
import Application from "./Application";
import Types from "./types";

const application = container.get<Application>(Types.Application);
application.run();

There’s more to inversify than just the code listed above, such as you can have multiple Service implementations and use named bindings to receive the one you want and more.

Decorators (attributes/annotations) in TypeScript

TypeScript experimental (enabled by setting “experimentalDecorators”: true within the tsconfig.json) enables a feature known as decorators, in C# we call them attributes and Java they’re annotations. Basically they are way to extend the functionality of classes, either by adding meta data or adding code to enable AOP type functionality.

To define a decorator we simple write a function which is evaluated, then called by the runtime allow for us to write AOP etc.

A decorator function takes different arguments depending upon whether it’s used on a class, property, parameter or method. Let’s assume we were to create a logging AOP decorator, we’d use the following signatures.

Let’s assume we’re writing one of those classic AOP functions, a log function.

Class Decorators

The class decorator has a simple form, a single argument of type Function. This argument is basically our class function.

function logClass(target: Function): any {
  // implementation
}

If our desire is to intercept and effect the creation of our classes then we will need to execute this Function and then in essence add our own prototypes or the likes. If our aim is to log the creation of this class, for example if we want to view performance numbers, then we can obviously log before and after creation via the decorator.

Let’s create a fairly standard looking class decorator which in this case has extended the logClass signature to be type safe

function logClass<T extends {new(...constructorArgs: any[]): any}>(ctor: T) {
  const newCtor: any = function (...args: any[]) {
    // pre ctor invocation
    const f: any = function () {
      return new ctor(...args);
    }
    f.prototype = ctor.prototype;
    const instance: any = new f();
    // post ctor invocation
    return instance;
  }
  newCtor.prototype = ctor.prototype;
  return newCtor;
}

If we want to get the name of the class we (at least in TypeScript) will need to have a line such as

const target: any = ctor;

and from this target we can now get the name of the type, for example

console.log(target.name);

In usages we simply write the following

@logClass
class MyClass {
}

Method Decorators

The method decorator is somewhat more complicated, as one would expect, as it takes three arguments, looking like this

function logMethod(
  target: any, propertyKey: string, 
  propertyDescriptor: PropertyDescriptor): PropertyDescriptor {
  // implementation
}

The first argument is the instance of the class, the second is the method name and the final one relates to the PropertyDescriptor parameters for the method which is of the following sample shape

{
  value: [Function],
  writable: true,
  enumerable: true,
  configurable: true
}

For a usage example we might write something like this

function logMethod(target: any, 
   propertyKey: string, 
   propertyDescriptor: PropertyDescriptor): PropertyDescriptor {
  const method = propertyDescriptor.value;
  propertyDescriptor.value = function (...args: any[]) {
    // pre method call
    const result = method.apply(this, args);
    // post method call
    return result;
  }
  return propertyDescriptor;
};

In usages we simply write the following

class MyClass {
   @logMethod
   run(): void {
   }
}

Parameter Decorators

We can apply a decorator to an argument/parameter of a method with a decorator with the parameters show below

function logParameter(
   target: any, propertyKey: string | symbol, 
   propertyIndex: number): void {
  // implementation
}

The target is the instance of the target object, the propertyKey is the name of the method the parameter we’re decorating is on.

Note: As per TypeScript documentation on this decorator – a parameter decorator can only be used to observe that a parameter has been declared on a method.

In usages we simply write the following

class MyClass {
   @logMethod
   run(@logParameter options: any): void {
   }
}

You’ll notice the addition of the logMethod in the example above. The thing is the parameter decorator in this case needs to work alongside the method decorator because the parameters within this decorator will simply be the instance of the object or prototype, the method name and the index of the parameter. There isn’t any way from these three parameters to directly get the value passed into the parameter, hence we’d probably tend towards using the logParameter to add a prototype or the likes to allow the logMethod to then query for these prototypes.

However we might also be able to utilities the reflect-metadata npm package to embed meta data alongside our types – we’ll look at this in another post.

Property Decorators

A property in TypeScript is a field in C# terms. The format of the function is shown below, as per other functions, the target is the object or prototype. The propertyKey is the name of the property/field the decorator’s associated with.

function logProperty(target: any, propertyKey: string): void {
  // implementation
}

In usages we simply write the following

class MyClass {
   @logProperty
   public running: boolean;
}

We can insert our own implementation of the property’s getter/setter in the following way

function logProperty(target: any, propertyKey: string): void {

  let value = target[propertyKey];
  const getter = () => {
    return value + " Doo";
  };

  const setter = (newVal: any) => {
    value = newVal;
  };

  if (delete target[propertyKey]) {
    Object.defineProperty(target, propertyKey, {
      get: getter,
      set: setter,
      enumerable: true,
      configurable: true
    });
  }
}

In the above we create our own getter and setter, then remove the existing property replacing with our own.

Further…

Decorators are (at the time of writing this) in stage 2 proposal state, see https://github.com/tc39/proposal-decorators and are different in implementation to those experimental features within TypeScript.

Apollo GraphQL client

Based upon our previous implementation(s) of a server it’s now time to write some client code.

  • yarn add apollo-client
  • yarn add apollo-cache-inmemory
  • yarn add apollo-link-http
  • yarn add graphql-tag
  • yarn add isomorphic-fetch
  • yarn add -D @types/isomorphic-fetch

Now let’s create a simple script entry (this extends the previous post’s scripts section)

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

Now let’s create the file client.ts which should look like this

import ApolloClient from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import gql from 'graphql-tag';
import fetch from 'isomorphic-fetch';

const cache = new InMemoryCache();
const link = new HttpLink({
  uri: 'http://localhost:4000/',
  fetch: fetch
})

const client = new ApolloClient({
  cache,
  link,
});

client.query({
  query: gql`
    {
    users {
      firstName
      lastName
    }
  }`
  })
  .then((response: any) => console.log(response.data.users));

The response.data.users should now output the array of User objects.

Here’s an example of a mutation

client.mutate({
  mutation: gql`
    mutation {
      create(user: {
        firstName: "Miner",
        lastName: "FortyNiner"
      }) {
        firstName
        lastName
      }
    }
  `
}).then((response: any) => console.log(response.data.create));

Note: I had lots of issues around the fetch code, with errors such as Invariant Violation:
fetch is not found globally and no fetcher passed, to fix pass a fetch for your environment like
https://www.npmjs.com/package/node-fetch.
. The addition of the isomorphic-fetch solved this problem.

Writing our first Apollo GraphQL server

In the previous posts we’ve seen how to build an express based server and eventually add GraphQL to it.

graphql-express is not the only option for implementing GraphQL servers, let’s now look at Apollo – I cannot say whether one library is better than the other as I’ve not used them enough to comment although.

Let’s go through the process of creating a new project for this, so carry out the following steps

  • Create a folder for your project
  • cd to that folder
  • Run yarn init -y
  • Run tsc –init
  • Add a folder named models and a file named user.ts (we’ll use the same model/data from the previous posts), here’s the code for this file
    export default class User {
      constructor(public firstName: string, public lastName: string) {
      }
    }
    
    export const stubData = [
      new User('Scooby', 'Doo'),
      new User('Fred', 'Jones'),
      new User('Velma', 'Dinkley'),
      new User('Daphne', 'Blake'),
      new User('Shaggy', 'Rogers'),
    ];
    

So that’s the basics in place for the support data and model, let’s now look at the specifics for Apollo.

We’re going to create a file for the resolvers named resolver.ts and here’s the code

import User, { stubData } from "./models/user";

export const resolvers = {
  Query: {
    users: () => stubData,
  },
  Mutation: {
    create: (parent: any, args: any): User => {
      const data = new User(args.user.firstName, args.user.lastName)
      stubData.push(data);
      return data;
    }
  }
}

As you can see, we specify the Query and Mutation separately and the code’s pretty much the same as the express-graphql implementation except in the create mutation parameters. In this case the parent will supply any parent nodes whilst the args supplies the parameters from the mutation call.

Now we’ll create the file server.ts which will have the (as I’m sure you guessed) the server code as well as the schema definition (Apollo names this typeDefs).

import { ApolloServer, gql } from "apollo-server";
import { resolvers } from "./resolvers";

const typeDefs = gql`
type User {
    firstName: String
    lastName: String
  }

  input UserInput {
    firstName: String
    lastName: String
  }

  type Mutation {
    create(user: UserInput): User
  }

  type Query {
    users: [User]
  }
`;

const server = new ApolloServer({ typeDefs, resolvers });

server.listen()
  .then(({ url }) => {
    console.log(`Server listening to ${url}`);
  });

Note that Apollo uses a template tag gql function to declare the GraphQL schema, which along with the resolves is passed into the ApolloServer, then we simply start the server.

If you now run yarn build followed by yarn run the server will run up with default port 4000. Navigating to http://localhost:4000/ will display the GraphQL playground.

So, as you can see, Apollo is very simple to set-up for use as a GraphQL server.

Adding GraphQL to our Express server

In the previous two posts, we firstly create a basic server, then extended this with REST functionality, now lets add GraphQL capabilities.

First off, run the following

  • yarn add express-graphql graphql
  • Add a folder named schema

With the schema folder add a new file userSchema.ts with the following code

import { buildSchema } from "graphql";

export const schema = buildSchema(`
  type User {
    firstName: String
    lastName: String
  }

  type Query {
    users: [User]
  }
`);

In the above code, we create a GraphQL schema based upon our User type, along with the type Query for us to use the User type.

Next we’ll create a folder named resolvers along with the file userResolver.ts. GraphQL uses resolvers to interact with the data via GraphQL (like the code in the indexController in the previous post).

import { stubData } from "../models/user";

export const userResolver = {
  users: () => {
    return stubData;
  }
}

Now let’s update the server.ts file by adding the GraphQL code, I’ll include the whole file here (at least the specifics for GraphQL)

import graphqlHTTP from "express-graphql";
import { schema } from "./schema/userSchema";
import { userResolver } from "./resolvers/userResolver";

const server = express();

server.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: userResolver,
  graphiql: true,
}));

const port = 4000;
server.listen(port,
  () => console.log(`Server on port ${port}`)
);

In the above we’ve specified graphiql: true which allows us to via the GraphIQL page using http://localhost:4000/graphql

Now if you type the following into the left hand (query) pane

{
  users {
    firstName
    lastName
  }
}

Running this from GraphIQL should output all our stubData.

We’ve essentially got the users method from our original code but now let’s add the equivalent of the create method, which in GraphQL terms is a mutation type.

In the userSchema.ts file, change the schema to look like this

export const schema = buildSchema(`
  type User {
    firstName: String
    lastName: String
  }

  input UserInput {
    firstName: String
    lastName: String
  }

  type Mutation {
    create(user: UserInput): User
  }

  type Query {
    users: [User]
  }
`);

We’ve added an input type UserInput along with the type Mutation. Next, within the userResolve.ts file change the userResolve to add the create function, as below

export const userResolver = {
  users: () => {
    return stubData;
  },
  create: (data: any) => {
    stubData.push(new User(data.user.firstName, data.user.lastName)); 
    return data.user;
  }
}

Let’s test this code by executing the following query via GraphIQL

mutation {
  create(user: {
    firstName: "Miner",
    lastName: "FortyNiner",
  }) {
    firstName
    lastName
  }
}