Categories
GraphQL JavaScript Nodejs

An Introduction to GraphQL

GraphQL is a query language for our API and a server-side runtime for running queries by using a type system for our data.

In this article, we’ll look at how to make basic queries to a GraphQL API.

Defining the API

We define an API by defining the types and fields for those types and provide functions for each field on each type.

For example, if we have the following type:

type Query {  
  person: Person  
}

Then we have to create a function for the corresponding type to return the data:

function Query_person(request) {  
  return request.person;  
}

Making Queries

Once we have a GraphQL service running, we can send GraphQL queries to validate and execute on the server.

For example, we can make a query as follows:

{  
  person {  
    firstName  
  }  
}

Then we may get JSON like the following:

{  
  "person": {  
    "firstName": "Joe"  
  }  
}

Queries and Mutations

Queries are for getting data from the GraphQL server and mutations are used for manipulating data stored on the server.

For example, the following is a query to get a person’s name:

{  
  person {  
    name  
  }  
}

Then we may get the following JSON from the server:

{  
  "data": {  
    "person": {  
      "name": "Joe"  
    }  
  }  
}

The field name returns a String type.

We can change the query as we wish if we want to get more data. For example, if we write the following query:

{  
  person {  
    name  
    friends {  
      name  
    }  
  }  
}

Then we may get something like the following as a response:

{  
  "data": {  
    "person": {  
      "name": "Joe",  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    }  
  }  
}

The example above has friends being an array. They look the same from the query perspectively, but the server knows what to return based on the type specified.

Arguments

We can pass in arguments to queries and mutations. We can do a lot more with queries if we pass in arguments to it.

For example, we can pass in an argument as follows:

{  
  person(id: "1000") {  
    name      
  }  
}

Then we get something like:

{  
  "data": {  
    "person": {  
      "name": "Luke"  
    }  
  }  
}

from the server.

With GraphQL, we can pass in arguments to nested objects. For example, we can write:

{  
  person(id: "1000") {  
    name  
    height(unit: METER)  
  }  
}

Then we may get the following response:

{  
  "data": {  
    "person": {  
      "name": "Luke",  
      "height": 1.9  
    }  
  }  
}

In the example, the height field has a unit which is an enum type that represents a finite set of values.

unit may either be METER or FOOT.

Fragments

We can define fragments to let us reuse complex queries.

For example, we can define a fragment and use it as follows:

{  
  leftComparison: person(episode: FOO) {  
    ...comparisonFields  
  }  
  rightComparison: person(episode: BAR) {  
    ...comparisonFields  
  }  
}  
​  
fragment comparisonFields on Character {  
  name  
  appearsIn  
  friends {  
    name  
  }  
}

In the code above, we defined the comparisonFields fragment which has the list of fields we want to include in each query.

Then we have the leftComparison and rightComparison queries which include the fields of the comparisonFields fragment by using the ... operator.

Then we get something like:

{  
  "data": {  
    "leftComparison": {  
      "name": "Luke",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    },  
    "rightComparison": {  
      "name": "Mary",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Mary"  
        },  
        {  
          "name": "Alex"  
        }  
      ]  
    }  
  }  
}

Using variables inside fragments

We can pass in variables into fragments as follows:

query PersonComparison($first: Int = 3){  
  leftComparison: person(episode: FOO) {  
    ...comparisonFields  
  }  
  rightComparison: person(episode: BAR) {  
    ...comparisonFields  
  }  
}  
​  
fragment comparisonFields on Character {  
  name  
  appearsIn  
  friends(first: $first) {  
    name  
  }  
}

Then we may get something like:

{  
  "data": {  
    "leftComparison": {  
      "name": "Luke",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Jane"  
        },  
        {  
          "name": "John"  
        }  
      ]  
    },  
    "rightComparison": {  
      "name": "Mary",  
      "appearsIn": [  
        "FOO",  
        "BAR"  
      ],  
      "friends": [  
        {  
          "name": "Mary"  
        },  
        {  
          "name": "Alex"  
        }  
      ]  
    }  
  }  
}

as a response.

The operation type may either be a query, mutation, or subscription and describes what operator we’re intending to do. It’s required unless we’re using the query shorthand syntax. In that case, we can’t supply a name or variable definition for our operation.

The operation name is a meaningful and explicit name for our operation. It’s required in multi-operation documents. But its use is encouraged because it’s helpful for debugging and server-side logging.

It’s easy to identify the operation with a name.

Conclusion

GraphQL is a query language that lets us send requests to a server in a clear way. It works by sending nested objects with operation type and name along with any variables to the server.

Then the server will return us the response that we’re looking for.

Operation types include queries for getting data and mutations for making changes to data on the server.

Categories
JavaScript Rxjs

More Rxjs Transformation Operators — Group and Map

Rxjs is a library for doing reactive programming. Creation operators are useful for generating data from various data sources to be subscribed to by Observers.

In this article, we’ll look at some transformation operators like groupBy , map , mapTo and mergeMap .

groupBy

The groupBy operator takes values emitted by the source Observable and then group them by the criteria that we set for them.

It takes 4 arguments. The first is the keySelector , which is a function that extracts the key for each item.

The second is an optional argument for the elementSelector , which is a function that extracts the return element for each item.

The 3rd argument is the durationSelector , which is an optional function that returns an Observable to determine how long each group should exist.

Finally, the last argument is the subjectSelector , which is an optional function that returns a Subject.

For example, we can use it as follows:

import { of } from "rxjs";  
import { groupBy, reduce, mergeMap } from "rxjs/operators";
const observable = of(  
  { id: 1, name: "John" },  
  { id: 2, name: "Jane" },  
  { id: 2, name: "Mary" },  
  { id: 1, name: "Joe" },  
  { id: 3, name: "Don" }  
).pipe(  
  groupBy(p => p.id),  
  mergeMap(group$ => group$.pipe(reduce((acc, cur) => [...acc, cur], [])))  
);

observable.subscribe(val => console.log(val));

In the code above, we called groupBy(p => p.id) to group the items emitted from the of Observable by id .

Then we have:

mergeMap(group$ => group$.pipe(reduce((acc, cur) => [...acc, cur], [])))

to get the grouped items together to be emitted by one Observable.

map

The map operator lets us map the values emitted by the source Observable to the other values and emits the resulting values as an Observable.

It takes up to 2 arguments. The first argument is the project function, which is required. The function takes the emitted value of the source Observable and the index of it and then returns what we want by manipulating those.

The second argument is optional. It’s the thisArg , which is used to define the this value for the project function in the first argument.

For example, we can use it as follows:

import { of } from "rxjs";  
import { map } from "rxjs/operators";
const observable = of(1, 2, 3);  
const newObservable = observable.pipe(map(val => val ** 2));  
newObservable.subscribe(x => console.log(x));

The code above takes the emitted values from observable , then pass it to the map operator via the pipe operator. In the callback, we passed into the map operator, we exponentiate the originally emitted value to the power of 2.

Then we can subscribe to an Observable that emits the new values and we get:

1  
4  
9

logged.

mapTo

The mapTo operator emits the given constant value for any source Observable’s emitted value.

It takes one argument, which is the value to emit.

For example, we can use it as follows:

import { of } from "rxjs";  
import { mapTo } from "rxjs/operators";
const observable = of(1, 2, 3);  
const newObservable = observable.pipe(mapTo("foo"));  
newObservable.subscribe(x => console.log(x));

The code above maps all the values from observable to the value 'foo' , so we get 'foo' 3 times instead of 1, 2 and 3.

mergeMap

The mergeMap operator takes the values emitted from a source Observable and then lets us combine it with the values of another Observable.

It takes up to 3 arguments. The first is a project function to project the values and return a new Observable.

The second argument is an optional argument that takes an resultSelector . We can pass in a function to select the values to emit from the result.

The third argument is the concurrency , which is an optional argument that specifies the maximum number of input Observables to be subscribed to concurrently. The default is Number.POSITIVE_INFINITY .

For example, we can use it as follows:

import { of } from "rxjs";  
import { mergeMap, map } from "rxjs/operators";
const nums = of(1, 2, 3);  
const result = nums.pipe(mergeMap(x => of(4, 5, 6).pipe(map(i => x + i))));  
result.subscribe(x => console.log(x));

The code above will get the values from the 3 values emitted from the nums Observable, then pass the values to the mergeMap ‘s callback function via the pipe operator. x will have the values from nums .

Then in the callback, we have the of(4, 5, 6) Observable, which have the values from combined from the nums Observable. i has the values from the of(4, 5, 6) Observable, so we the values from both Observables added together. We get 1 + 4, 1 + 5, 1 + 6, 2 + 4, 2 + 5, 2 + 6 and so on.

In the end, we should get the following output:

5  
6  
7  
6  
7  
8  
7  
8  
9

The groupBy operator takes values emitted by the source Observable and then group them by the criteria that we set for them. We can use it in conjunction with the mergeMap to combined the results grouped by the groupBy operator into one Observable.

The map operator lets us map the values emitted by the source Observable to the other values and emits the resulting values as an Observable.

The mapTo operator emits the given constant value for any source Observable’s emitted value.

Finally mergeMap operator takes the values emitted from a source Observable and then lets us combine it with the values of another Observable. Then we get an Observable with the values of both Observables combined together.

Categories
Express JavaScript Nodejs

Storing User Sessions on the Server with Express-Session

To store confidential session data, we can use the express-session package. It stores the session data on the server and gives the client a session ID to access the session data.

In this article, we’ll look at how to use it to store temporary user data.

Installation

express-session is a Node package. We can install it by running:

npm install express-session

Then we can include it in our app by adding:

const session = require('express-session');

Usage

The session function returns a middleware to let us store sessions. It takes an option object with the following properties:

cookie

Settings object for the session ID cookie. The default value is:

{ path: '/', httpOnly: true, secure: false, maxAge: null }.

It takes the following properties:

cookie.domain

It specifies the value for the Domain Set-Cookie attribute. No domain is set by default. Most clients will consider the cookie to apply only to the current domain.

cookie.expires

This specifies the Date object of the value for the Expires Set-Cookie attribute. No expiration date is set by default. This means the cookie will be deleted when the session ends.

If both expires and maxAge are set, then the last one defined if what’s used. expires shouldn’t be set directly. We should set maxAge .

cookie.httpOnly

Specifies the boolean value for the HttpOnly Set-Cookie attribute. When it’s truthy, the HttpOnly attribute is set. Otherwise, it’s not. By default, only HttpOnly attribute is set.

cookie.maxAge

The number of milliseconds to use when calculating the Expires Set-Cookie attribute. This is calculated by taking the current server time and adding maxAge milliseconds to it to calculate the Expires datetime. No maximum age is set by default.

cookie.path

Sets the Path Set-Cookie attribute value. This is set to / by default which is the root path of the domain.

cookie.sameSite

A boolean or string for the value of the SameSite Set-Cookie attribute. It can be:

  • true — will set the SameSite attribute to Strict for strict same site enforcement
  • false — won’t set the SameSite attribute
  • 'lax' — set the SameSite attribute to Lax for lax same-site enforcement
  • 'strict' set the SameSite attribute to Strict for strict same-site enforcement

cookie.secure

Boolean value for the Secure Set-Cookie attribute. The Secure attribute is set. Otherwise, it’s not.

Cookies won’t be sent over HTTP connects if this is set to true .

However, it’s recommended. If the app is hosted behind a proxy, then trust proxy must be set if secure is set to true .

genid

A function to generate a new session ID. The default value is a function that uses the uid-safe library to generate IDs.

name

The name of the session ID cookie to set in the response. The default value is 'connect.sid' .

proxy

Trust the reverse proxy when setting cookies via the X-Forwarded-Proto header.

The default value is undefined . Other possibles include:

  • true — the X-Forwarded-Proto header will be used
  • false — all headers are ignored and the connection is considered secure only if it’s a direct SSL/TLS connection
  • undefined — uses the 'trust proxy' setting from Express

resave

Forces the session to be saved back to the session store even if the session was never modified during the request.

This may create race conditions when a client makes 2 parallel requests to our server and changes made to the session on one request may be overwritten when the other request ends.

Defaults to true , but the default may change in the future. false makes more sense as the option.

rolling

Force a session identifier cookie to be set on every response. The expiration is reset to the original maxAge , resetting the expiration countdown.

Defaults to false .

When this is set to true and saveUnintialized option is false , the cookie won’t be set on a response with uninitialized session

saveUnitialized

Force a session that’s uninitialized to be saved to the store. A session is uninitialized when it’s new but not modified. Setting this to false reduces server storage usage and comply with laws that require permission before storing cookies.

secret

This is a required option for the secret to sign the session ID cookie. It can be a string or an array of multiple string secrets.

store

The session store instance. It defaults to a new MemoryStore instance.

unset

Controls the result of unsetting req.session through delete , setting to null , etc.

Defaults to 'keep' . The possible values are:

  • 'destroy' — the session will be deleted when the response ends
  • 'keep' — the session will be kept but modifications made during the request aren’t saved.

req.session

We access the session data by using req.session . The data is typically JSON, so nested objects are fine.

req.session comes with the following methods:

regenerate(callback)

We call this to regenerate the session. Once it’s called, a new session ID and Session instance will be initialized at req.session and the callback will be called.

destroy(callback)

Destroys a session. req.session will be unset. Once it’s called, the callback will be called.

reload(callback)

Reloads the session data from the store and re-populates the req.session object. Once it’s done, the callback will be called.

save(callback)

Saves a session back to the store, replacing the contents of the store with the contents in memory.

This usually doesn’t need to be called.

touch()

Updates the maxAge property. This shouldn’t be called usually as this is done automatically.

id

We can get the session ID with the id property.

cookie

This property has the cookie content. This also lets us alter the cookie for the user.

Cookie.maxAge

We can set the maxAge property to change the expiry time in milliseconds.

Cookie.originalMaxAge

We can use this to get the original maxAge value in milliseconds.

req.sessionID

We can get the session ID of the loaded session with sessionId .

Implementing our Own Session Store

Session store must implement EventEmitter with additional methods.

store.all(callback)

An optional method to get all sessions in the store as an array. The callback signature is callback(error, sessions) and it’s called once the session is retrieved.

store.destroy(sid, callback)

A required method to delete a session from the store given the session ID. The callback has the signaturecallback(error) . It’s called once the session is deleted.

store.clear(callback)

An optional method to delete all sessions from the store. The callback signature is callback(error) and it called once the store is cleared.

store.length(callback)

An optional method to count all the sessions in the store. The callback has the signature callback(error, len).

store.get(sid, callback)

A required method to get the session data by the session ID (sid ). The callback has the signature callback(error, session) .

The session is returned if found, otherwise returns null or undefined .

store.set(sid, session, callback)

A required method to set the session given the sid , which is the session ID. The callback has the signature callback(error) once the session is set.

store.touch(sid, session, callback)

This method is suggested to be implemented. This is used to signal to the store that the given session is active. The callback has the signature callback(error) .

Example

An example would be storing the number of views and keep that data for 365 days. We can do that as follows:

const express = require('express');  
const bodyParser = require('body-parser');  
const session = require('express-session');  
const app = express();  
app.set('trust proxy', 1)  
app.use(session({  
  secret: 'secret',  
  resave: true,  
  cookie: {  
    maxAge: 24 * 60 * 60 * 365 * 1000  
  }  
}))
app.use(bodyParser.json());  
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/', (req, res) => {  
  if (req.session.views) {  
    req.session.views++;  
  }  
  else {  
    req.session.views = 1;  
  }  
  res.send(`${req.session.views} views`);  
})
app.listen(3000);

In the code, we have the secret so that the cookie will be signed. Then in our route handler, we can get and set the data by getting and setting req.session.views , which we created.

Then we should see the number of views as we keep reloading the / route. It sets to expire in 365 days by setting maxAge, so the number will keep going up.

In the response header, we should get that the Set-Cookie response header has a value like:

connect.sid=s%3Ad6jfPu5awWj3EXPF-MdtU8cPzjOY5NRT.33nyXjKdShPAPyw9WWwY4sywP44IOX5SPSt2WUkH0cs; Path=/; Expires=Mon, 28 Dec 2020 00:47:31 GMT; HttpOnly

We have the value of the session ID and expiry time.

Conclusion

We can use the express-session package to keep session cookie data on the server-side.

There’re many options like the content of various cookie attributes and the time to expiry.

Other settings like the ID, whether to save cookie only in HTTPS and so on can be set.

The cookies will be stored in a session store. We can also implement our own store if we aren’t satisfied with the existing stores that are available for us to use.

Categories
JavaScript Rxjs

Some Useful Rxjs Creation Operators

Rxjs is a library for doing reactive programming. Creation operators are useful for generating data from various data sources to be subscribed to by Observers.

In this article, we’ll look at some creation operators from Rxjs.

Ajax

We can use the ajax() operator to fetch response objects returned from APIs.

For example, we can use it as follows:

const observable = ajax(`https://api.github.com/meta`).pipe()  
  map(response => {  
    console.log(response);  
    return response;  
  }),  
  catchError(error => {  
    console.log(error);  
    return of(error);  
  })  
);

observable.subscribe(res => console.log(res));

We pipe the data from the response with the map operator. Also, we can catch HTTP errors with the catchError operator.

Also, we can use ajax.getJSON() to simplify the operation as follows:

import { ajax } from "rxjs/ajax";  
import { map, catchError } from "rxjs/operators";  
import { of } from "rxjs";

const observable = ajax.getJSON(`https://api.github.com/meta`).pipe()  
  map(response => {  
    console.log(response);  
    return response;  
  }),  
  catchError(error => {  
    console.log("error: ", error);  
    return of(error);  
  })  
);

observable.subscribe(res => console.log(res));

Note that in both examples, we return the response in the callback of the map that we passed into the map operator.

It also works for POST requests:

import { ajax } from "rxjs/ajax";  
import { map, catchError } from "rxjs/operators";  
import { of } from "rxjs";

const observable = ajax({  
  url: "https://jsonplaceholder.typicode.com/posts",  
  method: "POST",  
  headers: {  
    "Content-Type": "application/json"  
  },  
  body: {  
    id: 1,  
    title: "title",  
    body: "body",  
    userId: 1  
  }  
}).pipe(  
  map(response => console.log("response: ", response)),  
  catchError(error => {  
    console.log("error: ", error);  
    return of(error);  
  })  
);

observable.subscribe(res => console.log(res));

As we can see, we can set headers and body of the request, so ajax can deal with most HTTP requests.

Errors can also be caught with the catchError operator that we pipe in:

import { ajax } from "rxjs/ajax";  
import { map, catchError } from "rxjs/operators";  
import { of } from "rxjs";

const observable = ajax(`https://api.github.com/404`).pipe()  
  map(response => {  
    console.log(response);  
    return response;  
  }),  
  catchError(error => {  
    console.log(error);  
    return of(error);  
  })  
);

observable.subscribe(res => console.log(res));

bindCallback

bindCallback converts a callback API to a function that returns an Observable.

It can convert a function with parameters to an Observable by emitting the parameters.

It takes 3 arguments. The first is a function, which takes a callback function as a parameter. Whatever is passed into the callback function will be emitted by the Observable.

The second argument is an optional resultSelector . We can pass in a function to select the emitted results here.

The last argument is an optional scheduler. We can pass in a scheduler if we want to change the way the callback function in the first argument is scheduled to be called.

import { bindCallback } from "rxjs";

const foo = fn => {  
  fn("a", "b", "c");  
};

const observableFn = bindCallback(foo);  
observableFn().subscribe(res => console.log(res));

Then we’ll see 'a' , 'b' and 'c' since we passed them into our fn callback function, which is a parameter of foo .

Then we return a function that returns an Observable with the bindCallback function. Then we can subscribe to the returned Observable.

defer

defer lets us create an Observable that are only created when a subscription is made.

It takes one argument, which is an Observable factory function. For example, we can write:

import { defer, of } from "rxjs";
const clicksOrInterval = defer(() => {  
  return Math.random() > 0.5 ? of([1, 2, 3]) : of([4, 5, 6]);  
});  

clicksOrInterval.subscribe(x => console.log(x));

Then we can have an Observable that either subscribes to of([1, 2, 3]) or of([4, 5, 6]) depending on whether Math.random() return 0.5 or less or bigger than 0.5.

empty

Creates an Observable that emits nothing to Observers except for complete notification.

It takes one optional argument, which is the scheduler that we want to use.

For example, we can use it as follows:

import { empty } from "rxjs";
const result = empty();  
result.subscribe(x => console.log(x));

Then we should see nothing logged.

Another example would be to emit the value 'odd' when odd numbers are emitted from the original Observable:

import { empty, interval, of } from "rxjs";  
import { mergeMap } from "rxjs/operators";const interval$ = interval(1000);  
const result = interval$.pipe(  
  mergeMap(x => (x % 2 === 1 ? of("odd") : empty()))  
);  
result.subscribe(x => console.log(x));

from

from creates an Observable from an array, array-like object, a promise, iterable object or Observable-like object.

It takes 2 arguments, which is an array, array-like object, a promise, iterable object or Observable-like object.

The other argument is an optional argument, which is a scheduler.

For example, we can use it as follows:

import { from } from "rxjs";
const array = [1, 2, 3];  
const result = from(array);result.subscribe(x => console.log(x));

We can also use it to convert a promise to an Observable as follows:

import { from } from "rxjs";

const promise = Promise.resolve(1);  
const result = from(promise);
result.subscribe(x => console.log(x));

This is handy for situations where we want to do that, like converting fetch API promises to Observables.

As we can see, the creation operators are pretty useful for turning various data sources to Observables.

We have the ajax operator for getting HTTP request responses. The bindCallback function turns callback arguments into Observable data. defer let us create Observables on the fly when something subscribes to the Observable returned by the defer operator.

Finally, we have the empty operator to create an Observable that emits nothing, and a from operator to create Observables from an array, array-like object, a promise, iterable object or Observable-like object.

Categories
JavaScript TypeScript

TypeScript Advanced Types — Nullable Types and Type Aliases

TypeScript has many advanced type capabilities and which make writing dynamically typed code easy. It also facilitates the adoption of existing JavaScript code since it lets us keep the dynamic capabilities of JavaScript while using the type-checking capability of TypeScript. There are multiple kinds of advanced types in TypeScript, like intersection types, union types, type guards, nullable types, and type aliases, and more. In this article, we look at nullable types and type aliases.

Nullable Types

To let us assign undefined to a property with the --strictNullChecks flag on, TypeScript supports nullable types. With the flag on, we can’t assign undefined to type members that don’t have the nullable operator attached to it. To use it, we just put a question mark after the member name for the type we want to use.

If we have the strictNullChecks flag on and we set a value of a property to null or undefined , then like we do in the following code:

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

let p: Person = {  
  name: 'Jane',  
  age: null  
}

Then we get the following errors:

Type 'null' is not assignable to type 'number'.(2322)input.ts(3, 3): The expected type comes from property 'age' which is declared here on type 'Person'

The errors above won’t appear if we have strictNullChecks off and the TypeScript compiler will allow the code to be compiled.

If we have the strictNullChecks flag on and we want to be able to set undefined to a property as the value, then we can make the property nullable. For example, we can set a member of an interface to be nullable with the following code:

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

let p: Person = {  
  name: 'Jane',  
  age: undefined  
}

In the code above, we added a question mark after the age member in the Person interface to make it nullable. Then when we define the object, we can set age to undefined. We can’t still set age to null . If we try to do that, we get:

Type 'null' is not assignable to type 'number | undefined'.(2322)input.ts(3, 3): The expected type comes from property 'age' which is declared here on type 'Person'

As we can see, a nullable type is just a union type between the type that we declared and the undefined type. This also means that we can use type guards with it like any other union type. For example, if we want to only get the age if it’s defined, we can write the following code:

const getAge = (age?: number) => {  
  if (age === undefined) {  
    return 0  
  }  
  else {  
    return age.toString();  
  }  
}

In the getAge function, we first check if the age parameter is undefined . If it is, then we return 0. Otherwise, we can call the toString() method on it, which is available to number objects.

Likewise, we can eliminate null values with a similar kind of code, for instance, we can write:

const getAge = (age?: number | null) => {  
  if (age === null) {  
    return 0  
  }    
  else if (age === undefined) {  
    return 0  
  }  
  else {  
    return age.toString();  
  }  
}

This comes in handy because nullable types exclude null from being assigned with strictNullChecks on, so if we want null to be able to be passed in as a value for the age parameter, then we need to add null to the union type. We can also combine the first 2 if blocks into one:

const getAge = (age?: number | null) => {  
  if (age === null || age === undefined) {  
    return 0  
  }  
  else {  
    return age.toString();  
  }  
}

Type Aliases

If we want to create a new name for an existing type, we can add a type alias to the type. This can be used for many types, including primitives, unions, tuples, and any other type that we can write by hand. To create a type alias, we can use the type keyword to do so. For example, if we want to add an alias to a union type, we can write the following code:

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

interface Employee {  
  employeeCode: number;  
}

type Laborer = Person & Employee;  
let laborer: Laborer = {  
  name: 'Joe',  
  age: 20,  
  employeeCode: 100  
}

The declaration of laborer is the same as using the intersection type directly to type the laborer object, as we do below:

let laborer: Person & Employee = {  
  name: 'Joe',  
  age: 20,  
  employeeCode: 100  
}

We can declare type alias for primitive types like we any other kinds of types. For example, we can make a union type with different primitive types as we do in the following code:

type PossiblyNumber = number | string | null | undefined;  
let x: PossiblyNumber = 2;  
let y: PossiblyNumber = '2';  
let a: PossiblyNumber = null;  
let b: PossiblyNumber = undefined;

In the code above, the PossiblyNumber type can be a number, string, null or undefined . If we try to assign an invalid to it like a boolean as in the following code:

let c: PossiblyNumber = false;

We get the following error:

Type 'false' is not assignable to type 'PossiblyNumber'.(2322)

just like any other invalid value assignment.

We can also include generic type markers in our type aliases. For example, we can write:

type Foo<T> = { value: T };

Generic type aliases can also be referenced in the properties of a type. For example, we can write:

type Tree<T> = {  
  value: T;  
  left: Tree<T>;  
  center: Tree<T>;  
  right: Tree<T>;  
}

Then we can use the Tree type as we do in the following code:

type Tree<T> = {    
  value: T,  
  left: Tree<T>;  
  center: Tree<T>;  
  right: Tree<T>;  
}

let tree: Tree<string> = {} as Tree<string>;  
tree.value = 'Jane';tree.left = {} as Tree<string>  
tree.left.value = 'Joe';  
tree.left.left = {} as Tree<string>;  
tree.left.left.value = 'Amy';  
tree.left.right = {} as Tree<string>  
tree.left.right.value = 'James';tree.center = {} as Tree<string>  
tree.center.value = 'Joe';tree.right = {} as Tree<string>  
tree.right.value = 'Joe';console.log(tree);

The console.log for tree on the last line should get us:

{  
  "value": "Jane",  
  "left": {  
    "value": "Joe",  
    "left": {  
      "value": "Amy"  
    },  
    "right": {  
      "value": "James"  
    }  
  },  
  "center": {  
    "value": "Joe"  
  },  
  "right": {  
    "value": "Joe"  
  }  
}

Nullable types are useful is we want to be able to assign undefined to a property when strictNullChecks flag is on when in our TypeScript compiler configuration. It’s simply a union type between whatever type you have and undefined . It’s denoted by a question mark after the property name. This means we can use type guards with it like any other union type. Note that nullable types don’t allow null values to be assigned to it since nullable types are only needed when strictNullChecks flag is on. Type alias let us create a new name for types that we already have. We can also use generics with type alias, but we can’t use them as standalone types.