TypeScript data types


Creative Commons License
This -TypeScript data types- tutorial is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License
Headlines
JavaScript

Rule(s)

Example

if(expression) {} // This evaluates to 'true' if 'expression' is not:

        null

        undefined

        NaN

        "" // Empty string

        0

        false

Rule(s)

Example

// 'A || B' returns the value 'A' if 'A' can be coerced into 'true'; it returns 'B' otherwise...
const port = process.env['PORT'] || 8080;
// Alternative:
const port = process.env['PORT'] ? process.env['PORT'] : 8080;
Type checking

Rule(s)

Example Base.ts.zip 

const re: RegExp = /^[A-Z]{3}$/; // 'RegExp' native type...
let bye: string = "BYE"; // 'string' primitive type...
console.assert(bye.match(re) !== null); // Exactly 3 capital letters...
bye = "CIAO";
console.assert(bye.match(re) === null);
const a: Array<boolean> = new Array();
a.push(false);
// a.push(bye); // Compilation error... but JavaScript execution works!
Type inference

Rule(s)

Example

let size: number; // Explicit typing...
let j = 0; // Type inference -> 'number'...
const my_array = []; // Implicit 'any' elements in 'my_array' -> bad idea...
const my_other_array = new Array<number>(size); // Type inference...
my_other_array.push(j);

Example

window.onscroll = function (e) { // 'Event' type is inferred for 'e'...
    // console.log(e.button); // Compilation error: "Property 'button' does on exist on type 'Event'."
}
// Versus:
window.onscroll = function (e) {
    console.assert(e.type === 'scroll'); // No compilation error...
}

Example (“lookup type”)

class C {
    a: boolean;
    b: C['a']; // Lookup type: type of 'b' is that of 'a', i.e., 'boolean'!
}
var versus let versus const

Rule(s)

Example (PURE JavaScript)

"use strict";
var well_declared_variable = "Strict mode is activated from all statement lines in the rest of this source file!";
ill_declared_variable = 2016; // The absence of 'var' raises an error at execution time thanks to the strict mode

Rule(s)

Example (PURE JavaScript)

const my_const = "It cannot change!";
my_const = "One says it cannot change!"; // Execution error
if(something) {
    let this_year = 2017; 
} // <- 'this_year' dies right there while 'var' (contrary to 'let') makes the variable living throughout its declaration function

Rule(s)

Example

const F = "Franck"; // 'F' has the *compilation* type "Franck" (inferred)
let B = "Barbier";   // 'B' has the type 'string' (inferred)
let FB = "FranckBarbier" as const; // 'FB' has the type 'string' (inferred)
// FB = "?"; // Compilation error because of 'as const'... -> somehow stupid as this stage?

const lasagna = {country: "Italy"}; // 'lasagna' has the type '{country: string}' (inferred)
lasagna.country = "France"; // 'const' has precise scope...
const foie_gras = {country: "France"} as const; // 'const' cast...
// foie_gras.country = "Italy"; // Compilation error!
// 'const' cast only applies to references to enum members, string, number, boolean, array or, object literals:
// let my_favorite_dish = lasagna as const; // Compilation error!
Type cast

Rule(s)

Example (tsconfig.json file)

"lib": [ // '"target": "ES6"' is enough
    "DOM",
    …

Example (casting)

// 'HTMLElement' and 'HTMLCanvasElement' come from the 'DOM' library
// Type cast is imposed by the fact that 'createElement' returns a 'HTMLElement' object:
let canvas: HTMLCanvasElement = window.document.createElement('canvas') as HTMLCanvasElement;

// Alternatively:
canvas = <HTMLCanvasElement>window.document.createElement('canvas');

Rule(s)

Example (tsconfig.json file)

"strictNullChecks": true,
…

Example (casting)

// By definition, 'getContext' returns 'null' or the canvas' context:
const canvas_context = canvas.getContext('2d');
if (canvas_context !== null) // Required by '"strictNullChecks": true'
    canvas_context.drawImage(image, 0, 0, image.width, image.height);

Example (alternative casting)

// By definition, 'getContext' returns 'null' or the canvas' context:
const canvas_context = <CanvasRenderingContext2D>canvas.getContext('2d'); // Required by '"strictNullChecks": true'
canvas_context.drawImage(image, 0, 0, image.width, image.height); // Potential failure! 
Primitive types

Rule(s)

Example

console.log(typeof true); // 'boolean'
console.log(typeof 2016); // 'number'
console.log(typeof "2016"); // 'string'
const Franck: string = "Franck";
console.log(`Hello ${Franck}`); // JavaScript 6 backquotes!

Rule(s)

Example

const my_bigint = 1234567890123456789012345678901234567890n; // Note 'n' suffix!

See also

null and undefined

Rule(s)

Example Base.ts.zip 

console.assert(null == undefined);
console.assert(null !== undefined);
let undefined_variable;
console.log(typeof undefined_variable); // 'undefined' is displayed...
console.log(typeof null); // 'object' is displayed...

See also

Enumerated types

Rule(s)

Example (PURE JavaScript)

const Medal = Object.freeze({ // No new field, no removable field, no writability, etc.
    Gold: Symbol("Gold"),
    Silver: Symbol("Silver"),
    Bronze: Symbol("Bronze")
});
console.assert(Object.isFrozen(Medal));
let award = Medal.Gold;
console.log(award !== Symbol("Gold")); // 'true' because 'Symbol' objects are unique...

Example

enum Medal {
    Gold = "Gold",
    Silver = "Silver",
    Bronze = "Bronze"
}
let award: Medal = Medal.Gold;
console.log(award); // 'Gold'

Example

enum Gateway_type {
    BPMN_complexGateway = 'bpmn:complexGateway',
    BPMN_eventBasedGateway = 'bpmn:eventBasedGateway',
    BPMN_exclusiveGateway = 'bpmn:exclusiveGateway',
    BPMN_inclusiveGateway = 'bpmn:inclusiveGateway',
    BPMN_parallelGateway = 'bpmn:parallelGateway'
}
…
if (!Object.values(Gateway_type).includes(gateway.$type as Gateway_type)) // 'values' => ES2017!
    throw new Error('Invalid gateway type among ' + JSON.stringify(Gateway_type));
Non-primitive types

Rule(s)

Example

/** JavaScript 'number' primitive type is 64-bit long based on the IEEE 754 standard */
// See also http://speakingjs.com/es5/ch11.html#number_representation
console.log(Number.MAX_VALUE);
const one: number = Number.parseInt("00000001", 2); // ES2015
if (Number.isNaN(one)) console.log('Number.isNaN(one)');
else console.log('one: ' + one); // '1'
const two: Number = new Number(1 << 1);
console.log('two(2): ' + two.toString(2)); // '10'
const zero: Number = new Number(1 >> 1);
console.log('zero: ' + zero); // '0'

Rule(s)

Example

/** JavaScript bitwise operators apply on the first significant 32 bits only! */
// How negative numbers are represented:
const minus_nine: Number = new Number((~9) | 1); // '00000000000000000000000000001001' -> '11111111111111111111111111110110' -> '11111111111111111111111111110111'
console.log('minus_nine: ' + minus_nine); // '-9'

// 32 significant bits representing the number are viewed as an *unsigned* 32-bit integer:
let x_: Number = new Number(-1 >>> 0); // Unsigned right shift that inserts '0' on the left (BTW: unsigned left shift does not exist!)
console.log('-1 >>> 0: ' + x_.toString(2)); // '11111111111111111111111111111111' -> (2^32 - 1) -> 4294967295

console.log(Number.MAX_SAFE_INTEGER.toString(2).length); // '53' since 'Number.MAX_SAFE_INTEGER' is equal to (2^53 - 1)
console.assert(Number.MAX_SAFE_INTEGER === -Number.MIN_SAFE_INTEGER);

console.log(Number.MAX_VALUE * 2 === Number.POSITIVE_INFINITY); // 'true'

console.log(isNaN(Math.sqrt(-1))); // 'true'

See also

Object type

Rule(s)

Example Base.ts.zip 

let o = {a: "a"};
console.assert(o.constructor === Object); // 'Object' function...
console.assert(Object.getPrototypeOf(o) === Object.prototype); // "Prototype inheritance"...

Rule(s)

Example

let o_ = Object.create(Object.prototype); // <=> 'let o_ = {};'
console.log(typeof o_); // 'object'

JavaScript objects may grow and slim!

Example (PURE JavaScript)

let Franck = {};
Object.defineProperty(Franck, "surname", {value: "Barbier", enumerable: true, configurable: true, writable: true});
Object.defineProperty(Franck, "nickname", {value: "Bab", enumerable: true, configurable: false, writable: false});
try {
    Franck.nickname = "Other nickname";
} catch (error) { // JavaScript, bug:
    console.log(error.message); // '"nickname" is read-only'
}
try {
    delete Franck.nickname;
} catch (error) { // JavaScript, bug:
    console.log(error.message); // 'property "nickname" is non-configurable and can't be deleted'
}
Franck.skill = "JavaScript"; // Dynamic extension
console.log(JSON.stringify(Franck)); // '{"surname":"Barbier","nickname":"Bab","skill":"JavaScript"}'
delete Franck.skill; // Dynamic suppression
if ("skill" in Franck === false)
    console.log("'Franck.skill' no longer exists...");

PropertyDescriptor

Example Base.ts.zip 

let non_configurable = {boring: "C'est la MAAF que je préfère..."};
Object.seal(non_configurable);
/* Bug in JavaScript ('property "boring" is non-configurable and can't be deleted')
and compilation error in TypeScript ('The operand of a 'delete' operator must be optional.'): */
// delete non_configurable.boring;

Example Base.ts.zip 

const UK = {};
Object.defineProperty(UK, "prime minister", {
    value: "Boris Johnson",
    enumerable: true,
    configurable: false,
    writable: false
});
Object.defineProperty(UK, "secret intelligence service head", {
    value: "Richard Moore",
    enumerable: true,
    configurable: false,
    writable: false
});
Object.defineProperty(UK, "secret intelligence service 007", {
    value: "James Bond",
    enumerable: false,
    configurable: false,
    writable: false
});
console.assert(UK.propertyIsEnumerable("constructor") === false);
console.assert(UK.propertyIsEnumerable("secret intelligence service 007") === false);

for (const property in UK) {
  // '"suppressImplicitAnyIndexErrors": true':
  console.log(`${property}: ${UK[property]}`); // "prime minister" and "secret intelligence service head" only...
}

getOwnPropertyNames

Rule(s)

  • Primitives of the Object type, e.g., getOwnPropertyNames, leverage introspection.

Example Introspection.js.zip 

const Get_attributes = (object) => {
    return Object.getOwnPropertyNames(object);
};

const Get_functions = (object) => {
    const functions = [];
    for (const f in object)
        if (typeof object[f] === "function" /*&& object.hasOwnProperty(f)*/) // Inherited functions (with comment) as well...
            functions.push(f);
    return functions;
};

const Display_attributes = (object) => {
    window.alert(Get_attributes(object).join(" - "));
};

const Display_functions = (object) => {
    window.alert(Get_functions(object).join(" - "));
};

Predefined objects (Document Object Model)

Rule(s)

Example

window.onload = this_is_the_main_program;
…
// Somewhere else:
function this_is_the_main_program() {
    console.log("All resources are available including downloaded images…");
    …

Example (window.screen)

this._map = window.document.getElementById('map'); // Get the display area (DOM must be ready)...
if(this._map)
    this._map.style.height = window.screen.height + "px";

Example (window.JSON)

// From 'Object' to 'String':
let my_string = window.JSON.stringify(my_object);
// From 'String' to 'Object':
let my_object = window.JSON.parse(my_string);

Example (window.Math)

window.alert(window.JSON.stringify(window.location.hostname)); // '"localhost"' may be displayed
window.alert(window.Math.E); // '2.718281828459045' is displayed
window.alert(window.Math.ceil(Math.E)); // '3' is displayed
Compilation-based types

Rule(s)

Example (null, undefined, and void)

let x: undefined = undefined;
let y: null = null;
function f(): void {
    return undefined;
}

Example (any)

let my_var: any;
console.assert(my_var === undefined, "Note that 'undefined' is both the type and its singleton value!");
my_var = {given_name: "Franck"};
console.assert(my_var.given_name === "Franck", "No compilation error...");

Rule(s)

Example

let my_other_var: unknown;
my_other_var = {given_name: "Franck"};
// console.assert(my_other_var.given_name === "Franck", "Compilation error: 'given_name' does not exist on type 'unknown'");
// if ('given_name' in my_other_var) ... // Compilation error!
// Type guard (type predicate) 'o is { given_name: string }':
function possess_given_name(o: any): o is { given_name: string } {
    return 'given_name' in o;
}
if (possess_given_name(my_other_var))
    console.log(my_other_var.given_name); // No compilation error...

Type guard

Rule(s)

Example (weak) Base.ts.zip 

const ws = new WebSocket("ws:127.0.0.1:1963", "FranckBarbier");
ws.onmessage = (event: MessageEvent) => {
    const d: any = JSON.parse(event.data); // What's inside 'event.data'?
    const high_quality: boolean = d.high_quality; // No type checking because 'd: any'...
};

Example (stronger) Base.ts.zip 

const ws = new WebSocket("ws:127.0.0.1:1963", "FranckBarbier");
ws.onmessage = (event: MessageEvent) => {
    const d: unknown = JSON.parse(event.data); // What's inside 'event.data'?
    // const high_quality: boolean = d.high_quality; // Compilation error because 'd: unknown'...
};

Example (best) Base.ts.zip 

interface _Data {
    high_quality: boolean;
}
type Data = _Data; // For pedagogy only...
function isData(d: any): d is Data {
    return 'high_quality' in d;
}
…
const ws = new WebSocket("ws:127.0.0.1:1963", "FranckBarbier");
ws.onmessage = (event: MessageEvent) => {
    const d: any /* or 'unknown' */ = JSON.parse(event.data);
    if (isData(d)) { // Allow access to 'high_quality' at *COMPILATION TIME*:
        const high_quality: boolean = d.high_quality;
    }
}

Type guard as predicate

Example (casting remains mandatory)

(model as DMN_Definitions).drgElement
    .filter(me => is_DMN_Decision(me)) // Type guard is used...
    .forEach(me => new Deep_learning_DMN_decision(me as DMN_Decision)); // Casting remains mandatory...

Example (type guard as predicate)

(model as DMN_Definitions).drgElement
    .filter(is_DMN_Decision) // Type guard as predicate...
    .forEach(me => new Deep_learning_DMN_decision(me)); // No casting!

Optional property

Rule(s)

Example (risk of failure in access to indexed property)

if (window['splash-screen'])
    window['splash-screen'].enable('circular');

Example (alternative)

window['splash-screen']?.enable('circular'); // No effect if 'splash-screen' does not exist...

Example

const o: any = {};
o.p?.something; // No bug!
// o.p.something; // Bug...

Example

function Hello(print?: (message: string) => void) {
    print?.("Hello");
}
Hello(); // No activation of 'print' function within 'Hello' function...
Hello(window.alert); // "Hello" is displayed...

See also

Non-null assertion operator

Rule(s)

Example

// I'm sure that 'this._scene.getObjectByName('dlh')' isn't 'null' or 'undefined':
console.assert(this._scene.getObjectByName('dlh')!.matrixAutoUpdate === false);

Rule(s)

Example (tsconfig.json file)

"strictPropertyInitialization": true,
…
class Student {
// Initialization must occur in constructor if 'strictPropertyInitialization' is set to 'true' else compilation errors:
    private _citizen_id: string;
    private _student_id: string;
    …
}

Example (alternative)

class Student {
    private _citizen_id!: string; // No initialization required by the compiler while 'strictPropertyInitialization' is set to 'true'...
    private _student_id: string;
    …
}

Example (overview of ! and ? operators)

interface Patient {
    medical_record?: string;
    nick_name: string;
}

function plastic_surgery_data(p: Patient): string {
    if (p.nick_name !== "Frankenstein")
        // Programmer claims that 'p.medical_record' isn't undefined:
        return p.medical_record!.normalize(); // '!' is required by '"strictNullChecks": true'
    return "Something else...";
}

function plastic_surgery_data_(p: Patient): string | undefined {
    if (p.nick_name !== "Frankenstein")
        // Generated JavaScript: 'if (p.medical_record !== undefined) return p.medical_record.normalize(); else return undefined;'
        return p.medical_record?.normalize(); // '?' is required by '"strictNullChecks": true'
    return "Something else...";
}

See also

Intersection and union types

Rule(s)

Example (union)

let my_var: number | string | null = null;

Example (union) Intersection_union_type.ts.zip 

interface Flying_fox {
    fly: () => void;
}
interface Fox {
    run: () => void;
}
const Observe = function (f: Flying_fox | Fox): void {
    if ('fly' in f) {
        f.fly();
    }
};

Example (intersection) Intersection_union_type.ts.zip 

interface Female { highly_skilled: boolean }
class Business_woman implements Female { highly_skilled = true; /* Implementation */ }
class /* 'interface' also works... */ Manager { /* Empty for test */ }

type FemaleAndManager = Female & Manager;
const fm: FemaleAndManager = new Business_woman;
console.assert(fm.highly_skilled);

Rule(s)

Example (multiple inheritance) Intersection_union_type.ts.zip 

interface Animal {
    children: Array<Animal>;
}
class Mammal implements Animal {
    children: Array<Animal> = new Array(); /* Implementation */
}
class Oviparous implements Animal {
    children: Array<Animal> = new Array(); /* Implementation */
    // eggs: any; // Compilation error!
}
const o: Mammal & Oviparous = new Mammal; // Property 'eggs' is missing in type 'Mammal' but required in type 'Oviparous'.