TypeScript Generics and Collections



Headlines
Arrays ⤳ from JavaScript Array to TypeScript Array<T>

Rule(s)

Example (PURE JavaScript)

let matrix = [[1, 2], [1, 2]];
let norm = 0;
matrix.forEach(function (element) {
    norm += element.reduce(function (sum, element) {
        return sum + element ** 2; // JavaScript 7 only! -> 'return sum + Math.pow(element, 2);'
    });
});
window.alert("Norm: ('forEach')" + Math.sqrt(norm));

norm = 0;
for (let element of matrix) {
    norm += element.reduce(function (sum, element) {
        return sum + element ** 2; // JavaScript 7 only! -> 'return sum + Math.pow(element, 2);'
    });
}
window.alert("Norm ('let'): " + Math.sqrt(norm));

const chromosomes = ["Genetic female - XX","Genetic male - XY"];
window.alert(chromosomes instanceof Array); // 'true' is displayed
window.alert(typeof chromosomes); // 'object' is displayed

chromosomes[-1] = "N'importe quoi !";
window.alert(chromosomes[-1]); // 'N'importe quoi !' is displayed
window.alert("chromosomes.length: " + chromosomes.length); // '3' is displayed!

const diseases = new Array("Turner's syndrome - X","Klinefelter syndrome - XXY");
console.assert(diseases.length === 2);

const genetics = [...chromosomes, ...diseases];
window.alert(JSON.stringify(genetics)); // '["Genetic female - XX","Genetic male - XY","Turner's syndrome - X","Klinefelter syndrome - XXY"]' is displayed!

const [given_name, surname] = ['Franck', 'Barbier'];
window.alert(typeof given_name + ": " + given_name); // 'string: Franck' is displayed...

const fb = ['Fr', 'Ba'];
const [gv = '?', sn = '?', nn = '?'] = fb;
window.alert(gv); // 'Fr' is displayed...
Sets ⤳ from JavaScript Set to TypeScript Set<E>

Rule(s)

Example (internally reusing TypeScript Set<E>) Set.ts.zip 

class Elephant {
    constructor(private readonly _name: string) {}
    toString() { return JSON.stringify(this); }
}

class Set_illustration<E> {
    private readonly _implementation: Set<E> = new Set;

    constructor(s?: Set<E>) {
        if (s === undefined)
            return;
        s.forEach((element: E) => {
            this._implementation.add(element);
        });
    }

    add(e: E) {
        return this._implementation.add(e);
    }

    erase(e: E) {
        return this._implementation.delete(e);
    }

    size() {
        return this._implementation.size;
    }

    strict_subset(s: Set_illustration<E>) { // The "current" set is strictly included in 's'...
        for (const element of this._implementation)
            if (!s._implementation.has(element))
                return false;
        return s !== this && s._implementation.size !== this._implementation.size;
    }

    symmetrical_difference(s: Set_illustration<E>) { // All stuff that is neither in the one nor the other...
        const symmetrical_difference: Set_illustration<E> = new Set_illustration(this._implementation);
        s._implementation.forEach((element: E) => {
            symmetrical_difference.add(element); // Union
        });
        const intersection: Set_illustration<E> = new Set_illustration;
        s._implementation.forEach((element: E) => {
            if (this._implementation.has(element))
                intersection.add(element);
        });
        // Formally, symmetrical difference is "union - intersection":
        intersection._implementation.forEach((element: E) => {
            symmetrical_difference._implementation.delete(element);
        });
        return symmetrical_difference;
    }
}

(function () {
    let Babar = null, Dumbo = null, Jumbo = null;
    const zoo: Set_illustration<Elephant> = new Set_illustration;
    zoo.add(Babar); // Compilation error with '"strict": true'...
    zoo.add(Dumbo); // Compilation error with '"strict": true'...
    zoo.add(Jumbo); // Compilation error with '"strict": true'...
    console.log("'zoo.size' ** 1: " + zoo.size);
    Babar = new Elephant("Babar");
    console.log("'zoo.size' ** 2: " + zoo.size);
    zoo.add(Babar);
    zoo.add(Babar);
    const Babar_bis = new Elephant("Babar");
    zoo.add(Babar_bis);
    console.log("'zoo.size' ** 3: " + zoo.size);
    Dumbo = new Elephant("Dumbo");
    Jumbo = new Elephant("Jumbo");
    const zoo_annex: Set_illustration<Elephant> = new Set_illustration;
    zoo_annex.add(Babar);
    zoo_annex.add(Dumbo);
    zoo_annex.add(Jumbo);
    const symmetrical_difference = zoo.symmetrical_difference(zoo_annex);
    console.log("'zoo.symmetrical_difference(zoo_annex)': ");
    console.log("\n'zoo.strict_subset(zoo_annex)' ** 1: " + zoo.strict_subset(zoo_annex));
    console.log("'zoo_annex.strict_subset(zoo)' ** 1: " + zoo_annex.strict_subset(zoo));
    zoo.erase(null); // Compilation error with '"strict": true'...
    zoo.erase(Babar_bis);
    console.log("\n'zoo.strict_subset(zoo_annex)' ** 2: " + zoo.strict_subset(zoo_annex));
    console.log("'zoo_annex.strict_subset(zoo)' ** 2: " + zoo_annex.strict_subset(zoo));
})();

Rule(s)

Example currencies.react.zip 

static _Links = [
    {
        path: '/' + 'Currencies',
        component: CurrenciesWrapper,
        data: {material_icon: 'payment'}
    },
    {
        path: '/' + 'New',
        component: CurrenciesController,
        data: {material_icon: 'fiber_new'}
    },
    {
        path: '/' + 'Currencies' + '/' + `${Currencies.Currencies[Currencies.Dollar].iso_code}`,
        component: CurrenciesInformation,
        data: {iso_code: Currencies.Currencies[Currencies.Dollar].iso_code, material_icon: 'attach_money'}
    },
    {
        path: '/' + 'Currencies' + '/' + `${Currencies.Currencies[Currencies.Euro].iso_code}`,
        component: CurrenciesInformation_, // Note: 'CurrenciesInformation === CurrenciesInformation_'
        data: {iso_code: Currencies.Currencies[Currencies.Euro].iso_code, material_icon: 'euro_symbol'}
    }
];
static _Components = [...new Set(CurrenciesMenu._Links.map(link => link.component))]; // 3 elements in the (re-computed) array...

Rule(s)

Maps ⤳ from JavaScript Map to TypeScript Map<K,V>

Example (JavaScript WeakMap versus Map)

// const polynomial = new WeakMap();
// polynomial.set(1, -12); // Bug...
// polynomial.set(39, 8);  // Bug...
const polynomial = new Map();
polynomial.set(1, -12); // OK...
polynomial.set(39, 8);  // OK...
window.alert(polynomial.get(39)); // '8'

Example (TypeScript Map<K,V>)

export enum NoLanguageCharacter_texture_type {
    Blurred = "Blurred",
    Grayed = "Grayed",
    None = "None",
    Normal = "Normal",
    Sobel = "Sobel"
}
…
protected readonly _textures: Map<NoLanguageCharacter_texture_type, THREE.CanvasTexture> =
    new Map<NoLanguageCharacter_texture_type,THREE.CanvasTexture>();
…
this._textures.set(NoLanguageCharacter_texture_type.Normal, new THREE.CanvasTexture(canvas));
this._textures.get(NoLanguageCharacter_texture_type.Normal).minFilter = THREE.LinearFilter;
…
for (let texture of this._textures.values())
    texture.dispose();
User-defined generics

Rule(s)

Example Inheritance_polymorphism.ts.zip 

class Sort_illustration<T extends Comparable<T>> {
    private readonly _implementation: Array<T> = new Array/*<T>*/(); // Don't forget to fill in somewhere else!

    sort(left: number, right: number): void { // Naive (slow) sort
        console.assert(left < right);
        for (let i: number = left; i < right; i++) {
            for (let j: number = i + 1; j <= right; j++) {
                if (this._implementation[i].compareTo(this._implementation[j]) === Comparable_.GreaterThan) {
                    let temp: T = this._implementation[i];
                    this._implementation[i] = this._implementation[j];
                    this._implementation[j] = temp;
                }
            }
        }
    }
}

Default type in generics

Rule(s)

Example

class Garden<V extends Vegetable = Broccoli> {
    private readonly _ground: Set<V> = new Set();

    public plant(v: V) {
        this._ground.add(v);
    }
}
…
const g = new Garden; // Inferred type is 'Garden<Broccoli>'
// g.plant(new Tomato); // Compilation error...

See also

Tuples

Rule(s)

Example Miscellaneous.ts.zip 

const chromosomes: Array<string> = ["Genetic female - XX", "Genetic male - XY"];
…
const diseases = new Array(Symbol("Turner's syndrome - X"), Symbol("Klinefelter syndrome - XXY")); // Type inference...
…
const genetics = [...chromosomes, ...diseases]; // Array of 'string | symbol'...
…
const mapping: [string | symbol, string | symbol] = [chromosomes[0], diseases[0]]; // Tuple...

Rule(s)

Example Miscellaneous.ts.zip 

const chromosomes_: ReadonlyArray<string> = ["Genetic female - XX", "Genetic male - XY"];
// chromosomes_.push("YY"); // Compilation error, content cannot be changed...
/* function switch_first_and_last<T>(array: readonly T[]): void {
    console.assert(array && array.length > 0);
    const temp: T = array[0];
    array[0] = array[array.length - 1]; // Compilation error because of 'readonly'...
    array[array.length - 1] = temp; // Compilation error because of 'readonly'...
} */
// Immutable tuple:
const center: readonly [number, number] = [0, 0];