Canvas art with TypeScript
Tags: webdev, typescript, art
Published: 2020-07-03 14:34:30

---
title: Canvas art with TypeScript
published: true
description: 📝 Notes from porting a JavaScript random art generator to TypeScript
tags: [webdev, typescript, art]
cover_image: https://www.chrismytton.uk/assets/images/random-art.png
canonical_url: https://www.chrismytton.uk/2020/06/06/canvas-art-in-typescript/
---

I ported a JavaScript "random art generator" I created a few years ago over to TypeScript. This post contains some notes from the process.

- See the project: [www.chrismytton.uk/art](https://www.chrismytton.uk/art/)
- Check out the code: [chrismytton/art on GitHub][github]

---

I've been learning TypeScript recently. As part of that I wanted to dig out some of my old JavaScript projects and port them to TypeScript. I find porting code to a new language is a good way to learn.

I found an old project that I created in 2014 which uses JavaScript and the Canvas API to create random pieces of art which change on every page load. The code itself is fairly straightforward, so it seemed like a good candidate for porting to TypeScript.

## Classes in TypeScript

TypeScript classes build on [ES6 classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). The major difference is that in TypeScript you need to explicitly declare the types of properties you're expecting on the class.

~~~typescript
class CanvasPainting {
  viewport: HTMLCanvasElement;
  ctx: CanvasRenderingContext2D;
}
~~~

If you try to use `this.viewport` without declaring the property TypeScript will tell you:

> Property 'viewport' does not exist on type 'CanvasPainting'.

I find having these properties explicitly defined actually makes it easier to figure out what the class might be doing internally. They provide useful documentation about what kind of data you can expect to find in each property.

## Index signatures

This is something I struggled with for a while. I was trying to dynamically call methods on my `Shapes` class using `this[shape]`, but TypeScript was giving this warning:

> Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Shapes'.
>
>   No index signature with a parameter of type 'string' was found on type 'Shapes'.

After reading various bits of the TypeScript documentation and some Stack Overflow answers I eventually figured out that I needed to define an index signature on my shapes class. This tells TypeScript what can be used to index this class, and what the indexing might return.

~~~typescript
class Shapes extends CanvasPainting {
  [key: string]: any;

  // ...
}
~~~

This tells TypeScript that you can index this class with a string, and it will return _something_. There might be a way to avoid using `any` here, but I haven't figured that out yet.

## Dealing with null values

TypeScript knows which methods can return `null` and will make you deal with those cases. If you try to call a method on a value that might be null then TypeScript will give you a warning.

You can avoid this warning by explicitly checking for `null` before using the value.

~~~typescript
class CanvasPainting {
  viewport: HTMLCanvasElement;
  ctx: CanvasRenderingContext2D;

  constructor(viewport: HTMLCanvasElement) {
    this.viewport = viewport;
    const ctx = viewport.getContext('2d');

    // getContext can return null, so check for that case.
    if (!ctx) {
      throw new Error("getContext('2d') failed");
    }
    this.ctx = ctx;
  }
}
~~~

Without this check for `null` TypeScript warns you that `Type 'null' is not assignable to type 'CanvasRenderingContext2D'.`.

It's easy to forget to check for `null` when writing JavaScript. TypeScript protects you from this class of error at the compile stage.

## Summary

I really like what I've seen so far with TypeScript. Working on little projects like this is a great way to get some experience with new tools.

I'd forgotten all about this fun little art project. It's nice to have given it a bit of polish and released it into the world, rather than it gathering dust on my hard drive.

See the project: [www.chrismytton.uk/art](https://www.chrismytton.uk/art/).


Check out the code: [chrismytton/art on GitHub][github].

[github]: https://github.com/chrismytton/art/blob/1f34e99d121f2c7dd698eb8c9d45da1e9b7f450c/src/random.ts