Skip to main content

Example - Bubble Sorter

This is a study note of Typescript The Complete Developers Guide, if you're looking for more details of these example, please see the course

v1 - Basic Sorter

sorter.ts
// Bubble Soter (Typescript)
class Sorter {
// collection: number[];
// constructor(collection: number[]) {
// this.collection = collection
// }

// * Typescript Constructor Shorthand
constructor(public collection: number[]) {}

sort(): void {
const { length } = this.collection;
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (this.collection[j] > this.collection[j + 1]) {
const leftHand = this.collection[j];
this.collection[j] = this.collection[j + 1];
this.collection[j + 1] = leftHand;
}
}
}
}
}

const sorter = new Sorter([10, 3, -5, 0]);
sorter.sort();
console.log(sorter.collection);

The compiled javascript, can see what tsc checked and removed

  • The type declaration of collection
  • Return type declaration
  • The constructor shorthand (Reference)
sorter.js
// Bubble Soter (Compiled Javascript)
"use strict";
class Sorter {
constructor(collection) {
this.collection = collection;
}
sort() {
const { length } = this.collection;
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (this.collection[j] > this.collection[j + 1]) {
const leftHand = this.collection[j];
this.collection[j] = this.collection[j + 1];
this.collection[j + 1] = leftHand;
}
}
}
}
}
const sorter = new Sorter([10, 3, -5, 0]);
sorter.sort();
console.log(sorter.collection);

v2 - Support String

Since string can't be replace in place in the Javascript, we have no choice to make the program determine what type it is in the cycle

soter-enhanced.ts
// Bubble Soter with string support (Typescript)
class Sorter {
constructor(public collection: number[] | string) { }

sort(): void {
const { length } = this.collection;

for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (this.collection instanceof Array) {
if (this.collection[j] > this.collection[j + 1]) {
const leftHand = this.collection[j];
this.collection[j] = this.collection[j + 1];
this.collection[j + 1] = leftHand;
}
}

if (typeof this.collection === 'string') {
if (this.collection[j].charCodeAt(0) > this.collection[j + 1].charCodeAt(0)) {
const leftHand = this.collection[j];
this.collection = this.collection.substr(0, j) + this.collection[j + 1] + this.collection[j] + this.collection.substr(j + 2)
}
}
}
}
}
}

And this is how the compiled javascript code looks like

sorter-enhanced.js
// Bubble Soter with string support (Compiled Javascript)
"use strict";
class Sorter {
constructor(collection) {
this.collection = collection;
}
sort() {
const { length } = this.collection;
for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (this.collection instanceof Array) {
if (this.collection[j] > this.collection[j + 1]) {
const leftHand = this.collection[j];
this.collection[j] = this.collection[j + 1];
this.collection[j + 1] = leftHand;
}
}
if (typeof this.collection === 'string') {
if (this.collection[j].charCodeAt(0) > this.collection[j + 1].charCodeAt(0)) {
const leftHand = this.collection[j];
this.collection = this.collection.substr(0, j) + this.collection[j + 1] + this.collection[j] + this.collection.substr(j + 2);
}
}
}
}
}
}

v3 - Separate swapping and comparison

Typescript can only help you to check the typing, guarad the type but can't help you to add checking logic to the code. To resolve the problem, you'll still need the refactor skill to decouple the components from the program.

collection.ts
export class NumbersCollection {
constructor(public data: number[]) {}

get length(): number {
return this.data.length;
}
compare(leftIndex: number, rightIndex: number): boolean {
return this.data[leftIndex] > this.data[rightIndex];
}

swap(leftIndex: number, rightIndex: number): void {
const leftHand = this.data[leftIndex];
this.data[leftIndex] = this.data[rightIndex];
this.data[rightIndex] = leftHand;
}
}

export class CharactersCollection {
constructor(public data: string) {}

get length(): number {
return this.data.length;
}

compare(leftIndex: number, rightIndex: number): boolean {
return (
this.data[leftIndex].toLowerCase() > this.data[rightIndex].toLowerCase()
);
}
swap(leftIndex: number, rightIndex: number): void {
const characters = this.data.split('');

const leftHand = characters[leftIndex];
characters[leftIndex] = characters[rightIndex];
characters[rightIndex] = leftHand;

this.data = characters.join('');
}
}

sorter.ts
import {NumbersCollection, CharactersCollection} from 'collections"


interface Sortable {
length: number;
compare(leftIndex: number, rightIndex: number): boolean;
swap(leftIndex: number, rightIndex: number): void;
}

export class Sorter {
constructor(public collection: Sortable) {}

sort(): void {
const { length } = this.collection;

for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (this.collection.compare(j, j + 1)) {
this.collection.swap(j, j + 1);
}
}
}
}
}

const numbersCollection = new NumbersCollection([10, 3, -5, 0]);
const num_sorter = new Sorter(numbersCollection);
num_sorter.sort();
console.log(numbersCollection.data);

const charactersCollection = new CharactersCollection('Xaayb');
const char_sorter = new Sorter(charactersCollection);
char_sorter.sort();
console.log(charactersCollection.data);

v4 - Guard with Abstract Class

export abstract class Sorter {
abstract compare(leftIndex: number, rightIndex: number): boolean;
abstract swap(leftIndex: number, rightIndex: number): void;
abstract length: number;

sort(): void {
const { length } = this;

for (let i = 0; i < length; i++) {
for (let j = 0; j < length - i - 1; j++) {
if (this.compare(j, j + 1)) {
this.swap(j, j + 1);
}
}
}
}
}
import { Sorter } from './sorter-type';

export class CharactersCollection extends Sorter {
constructor(public data: string) {
super();
}

get length(): number {
return this.data.length;
}

compare(leftIndex: number, rightIndex: number): boolean {
return (
this.data[leftIndex].toLowerCase() > this.data[rightIndex].toLowerCase()
);
}

swap(leftIndex: number, rightIndex: number): void {
const characters = this.data.split('');

const leftHand = characters[leftIndex];
characters[leftIndex] = characters[rightIndex];
characters[rightIndex] = leftHand;

this.data = characters.join('');
}
}

export class NumbersCollection extends Sorter {
constructor(public data: number[]) {
super();
}

get length(): number {
return this.data.length;
}

compare(leftIndex: number, rightIndex: number): boolean {
return this.data[leftIndex] > this.data[rightIndex];
}

swap(leftIndex: number, rightIndex: number): void {
const leftHand = this.data[leftIndex];
this.data[leftIndex] = this.data[rightIndex];
this.data[rightIndex] = leftHand;
}
}
import { NumbersCollection, CharactersCollection } from './sorter';

const numbersCollection = new NumbersCollection([50, 3, -5, 0]);
const sorter1 = new Sorter(numbersCollection);
sorter1.sort();
console.log(numbersCollection.data);

const charactersCollection = new CharactersCollection('Xaayb');
const sorter2 = new Sorter(charactersCollection);
sorter2.sort();
console.log(charactersCollection.data);