Skip to content

What's new

Alex D edited this page Dec 15, 2024 · 7 revisions

- indexes for classes and interfaces, properties for interfaces

class Test {
    // declare index (to assigning get/set methods to it)
    [index1: number]: string;
    
    get(index: number): string {
        return "index";
    }

    set(index: number, value: string) {
    }

    get val(): string {
        return "prop";
    }
}

interface ITest {
    [index1: number]: string;

    get val(): string;
}

const t = new Test();
print(t[10]);

const ti: ITest = t;
print(ti[10]);
print(ti.val);

- no need to define 'main' function

const arr = [1, 2, 3, 4, 5];
for (const b of arr)
    print(b);

- Accessor for object fields

let obj = {
    p: 1.0,
    get value() { return this.p; },
    set value(v: number) { this.p = v; },
}
  • Class static block
class C {
    static x: number;
    static {
        C.x = 1;
    }
}

- cast from Union Types

let a: string | number = 5;
let b: string = a; // b is "5"

- All functions without types are generics

static class Array {
    public of(...arg) {
        return arg;
    }

    public from(arrayLike) {
        return [...arrayLike];
    }       
}

- Native types aliases

// byte, short, ushort, int, uint, long, ulong, char, i8, i16, i32, i64,
// u8, u16, u32, u64, s8, s16, s32, s64, f16, f32, f64, f128, half, float, double, index

const s1: s8 = -1;
const s2: u16 = 2;
const s3: i32 = 3;
const s4: f64 = 1.0;

- Reference types (aka pointers)

let a = [1, 2, 3];
const view: Reference<TypeOf<1>> = ReferenceOf(a[1]);
const data = LoadReference(view);
const data1 = LoadReference(view[1]);

- Accessor

class Person {
    static accessor sname: string;
    accessor name = "no value";
    constructor(name: string) {
        this.name = name;
    }
}

- Explicit Resource Management

function main()
{
    using file = new TempFile(".some_temp_file");
    print("done.");
}

class TempFile {
    #path: string;
    #handle: number;
    constructor(path: string) {
        this.#path = path;
        this.#handle = 1;
    }
    // other methods
    [Symbol.dispose]() {
        // Close the file and delete it.
        this.#handle = 0;
        print("dispose");
    }
}

- Literal Type Widening

function main()
{
    let a: 10 = 11; // error
    let b = 11; // ok
    b = 10; // ok

    print("done.");
}

- Build option --emit=exe in tsc to generate executable file

tsc --opt --emit=exe <file>.ts

- Shared libraries with Import

Export for functions (from previous example)

// ./shared_lib can point to shared_lib.ts file or shared_lib.dll file (compiled with tsc --emit=dll shared_lib.ts command)
import './shared_lib'

function main()
{
	test1();
}

- Shared libraries

shared_lib.ts - shared library file:

export function test1()
{
	print("Hello World!");
}
  • Load shared library
function LoadFunction(dllName: string, funcName: string)
{
	LoadLibraryPermanently(dllName);
	return SearchForAddressOfSymbol(funcName);
}

let test1: () => void = LoadFunction("./shared_lib.dll", "test1");

function main()
{
	test1();
}

- Debug information: option --di in tsc

tsc --opt_level=0 --di --emit=obj <file>.ts

- Logical Assignments

function foo1(f?: (a: number) => number) {
    f ??= ((a: number) => a)
    f(42);
}

function foo2(f?: (a: number) => number) {
    f ||= ((a: number) => a)
    f(42);
}

function foo3(f?: (a: number) => number) {
    f &&= ((a: number) => a)
    f(42);
}

function main() {
    foo1();
    foo2();
    foo3((a: number) => a * 2);
}

- Optional type in tuple

function main() {
    type StaffAccount = [number, string, string, string?];

    const staff: StaffAccount[] = [
        [0, "Adankwo", "adankwo.e@"],
        [1, "Kanokwan", "kanokwan.s@"],
        [2, "Aneurin", "aneurin.s@", "Supervisor"],
    ];

    for (const v of staff) print(v[0], v[1], v[2], v[3] || "<no value>");

    assert(staff[2][3] == "Supervisor");

    print("done.");
}

- union type in yield

function* g() {
  yield* (function* () {
    yield 1.0;
    yield 2.0;
    yield "3.0";
    yield 4.0;
  })();
}

function main() {
    for (const x of g())
        if (typeof x == "string")
            print("string: ", x);
        else if (typeof x == "number")
            print("number: ", x);
}

- Well-Known Symbols

  • toPrimitive
    const object1 = {

        [Symbol.toPrimitive](hint: string) : string | number | Boolean {
            if (hint === "number") {
                return 10;
            }
            if (hint === "string") {
                return "hello";
            }
            return true;
        }

    };

    print(+object1); // 10        hint is "number"
    print(`${object1}`); // "hello"   hint is "string"
    print(object1 + ""); // "true"    hint is "default"
  • interator
class StringIterator {
    next() {
        return {
            done: true,
            value: ""
        };
    }
    [Symbol.iterator]() {
        return this;
    }
}

function main() {
    for (const v of new StringIterator) { }
}

- Generic methods

class Lib {
    static max<T>(a: T, b: T): T {
        return a > b ? a : b;
    }
}

function main() {
    assert(Lib.max(10, 20) == 20);
    assert(Lib.max("a", "b") == "b");
    assert(Lib.max<number>(20, 30) == 30);
    print("done.");
}