This is a follow-up tutorial to the Breakout OOP project. The goal of this tutorial is to convert the Breakout OOP project from vanilla JS to TypeScript.
What is TypeScript? Type script is a type-safe version of JavaScript.
What are types and what does it mean to be type-safe? The values you assign to any variable is has a type. The same is true for the values returned from functions and the parameter values defined by functions. All of these things have a type.
JavaScript is a dynamic language, meaning any variable can hold any type. You can assign a variable a number on one line of code and a string on the next line, for example:
let x = 88
x = 'Hello World!' // No problem here!
This might seem like an advantage but in reality, it is a source of many common errors! In a type-safe language when a variable has been declared its type is also declared, and the type can not be changed! For example, the code below is written in TypeScript:
let x = 88
x = 'Hello World!' // Error can't assign type String to variable type number!
In the TypeScript example, the error is spotted before we run our program!
Why learn Typescript? TypeScript is the industry's best practice and is used professionally on almost every professional project over vanilla JS. Why? Because catching errors early makes more reliable products!
TypeScript does not run in a browser. Instead, your TypeScript files need to be converted to vanilla JavaScript first.
To use TypeScript you need to implement a compiler. The instructions here use Webpack.
To follow this tutorial you need a project that uses Webpack. You'll use Webpack to compile your TypeScript and bundle your code as vanilla JS.
Follow these steps.
https://webpack.js.org/guides/typescript/
npm install --save-dev typescript ts-loader
Create:
tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node"
}
}
Modify webpack.config.js
module.exports = {
entry: './src/main.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
Notice main.js changed to ./src/main.ts
.
You will have two sets of code. Your source code will be your TypeScript files, these are the files you will edit. You will also have your distribution code, which is code that is generated by the bundler and compiled from your TypeScript files.
Your source code will go in the src/
directory and the distribution code will go in the dist/
directory.
You will only edit the files in the src/
directory.
Typescript files use the .ts
extension.
Make those folders now if you haven't.
Place all of your JS files in the src/
.
Typescript files use the .ts
file extension. Change the file names of all of the files in the src/
director so they end with the .ts
file extension.
Great! You've just created all of your TypeScript files!
JavaScript is a subset of the TypeScript language. Any JS you write should work as TypeScript.
You aren't taking advantage of TypeScripts type safety. Go through your code and add types where needed. Here are some examples.
Follow the guide here: https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html
Below are some examples to get you started.
Variable types
let x: number = 120
let name: string = 'John Friend'
const ball: Ball = new Ball()
Notice that a class is a type!
Function types
This function takes two parameters a and b both are type numbers. It returns a number.
The second function doesn't return anything so the type is void!
function exampleFunc(a: number, b: number): number {
return a + b
}
function otherFunc(): void {
console.log('Hello')
}
Classes
Classes are their type!
A class will define properties and methods. Properties have a type, and methods will have parameter types and return types.
Here is an example of the Ball from Breakout.
Notice the properties and their types are declared inside the class but outside the constructor or other method. Notice the value is not set here!
Methods follow the same convention as functions.
Notice that the ctx
is set to type any
. If there's a situation where you don't have a type definition for something type any
as a fallback.
class Ball extends Sprite {
// Declare class properties here!
radius: number
dx: number
dy: number
constructor(x: number, y: number, radius = 10, color = 'blue') {
super(x, y, radius * 2, radius * 2, color)
// Properties declared above are initialized here
this.radius = radius
this.dx = 2
this.dy = -2
}
move() {
this.x += this.dx
this.y += this.dy
}
render(ctx: any) { // Override
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
}
When defining a variable that stores an instance of a class the class is the type!
import Ball from './Ball'
// Notice the type here!
const ball: Ball = new Ball()
When you convert to Typescript you will need to remove the file extension on your import statements.
This:
import Ball from './Ball.js'
Becomes:
import Ball from './Ball'
In Typescript Arrays are typed. This means that an array can only store one type. For example an array of numbers:
const nums: number[] = [1,2,3,4]
An array of string:
const names: string[] = ['A', 'B', 'C']
For an array of arrays the type might look like this:
const grid: number[][] = [[1,2,3], [4,5,6]]
Linting is a crucial step in maintaining code quality and consistency when working with TypeScript. TypeScript can be seamlessly integrated with popular linting tools like ESLint and TSLint. Here's how to set up linting for your TypeScript project:
-
Install Dependencies:
- Install ESLint and TypeScript if you haven't already.
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
- Install ESLint and TypeScript if you haven't already.
-
Configuration:
- Create an ESLint configuration file (
.eslintrc.js
) in your project directory. - Configure it to use the TypeScript parser and TypeScript-specific rules:
module.exports = { parser: "@typescript-eslint/parser", plugins: ["@typescript-eslint"], extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], };
- Create an ESLint configuration file (
-
Run Linter:
- Use the
eslint
command to lint your TypeScript files:npx eslint your-file.ts
- Use the
Linting helps catch common errors, enforces coding standards, and enhances code readability. You can also set up custom rules and integrate linting into your build process for real-time feedback.
Feel free to check out the TypeScript ESLint docs!
You'll need to refer to the TypeScript docs in some cases. Take a look at them here: