# Gizlang for TypeScript programmers

Gizlang uses the spelling of TypeScript. This page shows only the differences. TypeScript
features that are not on this page are compile errors. They never get a different meaning.
`giz check FILE` gives the line, the rule and usually the fix.

This page is about `.giz` files: every form compiles to static native code. A `.ts`, `.mts` or `.cts` file keeps its
TypeScript meaning on the JavaScript compatibility engine, with the types erased ([COMPILER: JavaScript entry](../internals/compiler.md#javascript-entry)).

**Types.** `i64` and `f64` (`number` is `f64`), `u64`, `bool`, `string`, `bytes`, `Vec<T>`
(`T[]`). A `string` is UTF-8. Its `.length` and its indexes count bytes. There are no implicit
conversions. Use `i64(x)`, `f64(x)` and `string(x)` (a number or bool as text). Integer `/`
truncates. An integer literal is an `i64`: a `let sum = 0` that later adds a `number` is `let sum = 0.0` or
`let sum: number = 0`. `a ** b` (and `**=`) is `a.pow(b)`: libm pow on `f64`, exact on `i64` (`b >= 0`, overflow is a fault).
Overflow and bad indexes stop the program: they are faults, not values. `===` compares content: scalars, strings, and
the fields of records, unions and Vecs. `===` on class instances (`Ref` values) compares identity. Records with hidden fields, views and functions have no `===`.

**Records and unions** are values. Assignment copies them. They are never shared: where TypeScript would show a change of a copy through another name (`const b = a; b.x = 1;`, or `m = a; m.x = 1;` with `a` read after), the compiler refuses it and names a class, which is shared. An operator on a
record calls its method of that name: `a + b` is `a.add(b)` (`- * / ** < <= > >= -x`: sub mul div pow lt le gt ge neg).
```gizlang
type Line = { sku: string; qty: i64; };
type Status = | { kind: "open"; } | { kind: "paid"; amount: i64; };

function main(): void {
    const s = Status.paid(5);                  // or an object literal with an expected type
    const line: Line = { sku: "A1", qty: 1 };
    const l2 = { ...line, qty: 2 };            // spread a value
    const xs = [1, 2];
    const ys = [3];
    const all = [0, ...xs, 9, ...ys];          // join vectors in order: [0].concat(xs).concat([9]).concat(ys)
    print(`${s.kind === "paid"} ${l2.qty} ${all.length}`);
}
```
A `let` local changes in place at any path: `o.lines[i].qty = 3; o.lines.push(l);`. A
function changes the value of its caller only through a `mut` parameter:
`function add(o: mut Order, l: Line)`. An inner scope cannot declare a name again
(`E_SHADOW`). You cannot assign to a `const`. `let x: T;` declares a local with no value yet: an optional type starts
`undefined`, any other type its zero value (`0`, `""`, `false`, `[]`, an empty Map, a record of zero fields), where
TypeScript refuses a read before the first assignment. A class instance has no zero value, so `let c: C;` is an error.

A `const` made from an object or array literal can change one step in: `o.f = x`, `v[i] = x`, `v.push(x)`. This is
allowed only when nothing else holds the value: no other name, argument or lambda. A `return` or a spread may hold it.
Otherwise the `const` stays constant, because a copy would not see the change that TypeScript shows.

An object spread can call a function. The call runs once. It must be the first
expression that runs in the statement and must run unconditionally. The compiler
rejects a call spread when holding it before the statement would change this order.

**Classes** are objects, as in TypeScript: every name of an instance shares it, and `===` compares identity.
- The fields, and the `public x: T` parameters of a constructor, make the record. `new Point(1, 2)` runs the
  constructor.
- A method gets `this`, the instance, and changes it in place.
- A getter `get area()` reads as `p.area`, and a setter `set area(v)` runs for `p.area = v`. Static members are reached as `Point.origin()`.
- In the constructor, `this` exists from the statement where the last field with no initializer gets its value
  (`this.x = x;`).
- A generic class `class Box<T>` is generic in its record, constructor and methods: `new Box(3)` is a `Box<i64>`, and a
  method can have type parameters of its own.
- There is no `extends` (no inheritance). `implements` names interfaces that the methods implement.
```gizlang
class Counter {
    constructor(private count: i64) {}
    add(n: i64): void { this.count += n; }
    get value(): i64 { return this.count; }
}

function main(): void {
    const c = new Counter(1);
    const d = c;
    d.add(2);
    print(`${c.value}`);   // 3
}
```
**Enums** are numbers or strings. `enum Color { Red, Green = 5, Blue }` makes `Color.Blue` 6, and the type `Color` is an
`i64`. `enum Dir { Up = "UP" }` makes a `string`. A **literal union** (`"a" | "b"`, `1 | 2`) is the type of its
literals.

An **untagged union** `A | B` (`string | number`, `string[] | boolean`) holds a value of one of its members. A value
of a member's type is one where the union is expected. `typeof x === "string"` (or `!==`) narrows `x` to that member,
as `kind` narrows a union: inside the `if`, and after an `if` that returns, once one member is left. `typeof` names
`"number"`, `"boolean"`, `"string"` or `"object"` (every other type), so two members of one name (`number | i64`, two
records) are an error: use a union with `kind`. `typeof x` is only compared with a name.

A **tuple** `[A, B]` (up to six items, labels allowed) is `Tuple2<A, B>` of gizlang:core. `[a, b]` makes one where it is
expected, and where nothing is expected its items have different types (`new Map([["a", 1]])`). `t[0]` reads an item.
`const [a, , c] = t;` binds items of a tuple or a Vec.

**`async` and `await`**: an async function runs to its end when it is called. So `Promise<T>` is `T`, and `await e` is
`e`: `Promise.all(xs)` and `Promise.resolve(x)` are their argument. Concurrent work uses `Task` (`Task.zip`, `Task.thread`).

**Module-level `let`** is state of the module, such as `let count = 0;` or `let names: string[] = [];`.
- Its functions read and assign it. Its initializer runs at its first use.
- It changes only by assignment (`names = [...names, n]`). Only the functions of its own module reach it.
- Under `giz live` it keeps its value across code changes.

A **module `const`** of one literal is that literal at each use. Any other value (`const NAMES = ["a", "b"];`, an
object, a call) is computed once, at its first use, and no assignment changes it; other modules read it too.

**`as`, `readonly`**: `e as T` is checked, as `e satisfies T` is (there is no unchecked cast). `as const` changes
nothing, and `readonly` on a field or a type changes nothing: a value is never changed through another name anyway.

**match** reads a union. Write one arm for each case and `{}` for no action. There is no
default arm. `status.kind === "paid"` (or `!==`) tests one case, and the compiler checks the name.
```gizlang
type Status = | { kind: "open"; } | { kind: "paid"; amount: i64; };

export function paid(status: Status): i64 {
    match (status) { Status.open() => { return 0; } Status.paid(amount) => { return amount; } }
}
```
`status.kind === "paid"` also narrows a `const` or parameter, so `r.value` reads the case:
- in `if (r.kind === "ok") { ... }`;
- after `if (r.kind === "err") { return ...; }`, once one case is left (each such `if` rules out its case).

Tests joined by `&&`, `||` and `!` narrow too. In `a.kind === "ok" && a.value > 0`, the right side sees `a` ok. After
`if (a.kind === "err" || a.value < 0) { return ...; }`, `a` is ok. Inside one expression (`?:`, `&&`, `||`, `?.`) a
`let` narrows too, because no assignment can run there. An `if` block narrows only a `const` or parameter.

A `while (true)` (or `for (;;)`) with no `break` does not end, so a function needs no `return` after it.

**TypeScript forms** that lower onto the forms above:
- `` `n=${n}` `` is `"n=" + string(n)`. A hole takes what `string(x)` takes. The text may hold
  newlines; `` \` `` and `\$` are the characters.
- `c ? a : b` runs only the branch it picks.
- `x ?? y` takes an `Option<T>` x (TypeScript's `T | undefined`). It gives the value of x when there is one, else y.
  y runs only then.
- `switch (x) { case a: case b: ...; break; default: ... }` is an `if (x === a || x === b)` chain.
  A case ends with `break`, `return` or `continue`, or is the last. There is no fall-through
  into a case with statements, and `break` leaves the switch only at the end of a case.
- A `switch (u.kind)` whose cases name every case of the union, each ending in `return`, needs no `default`. It also
  needs no `return` after it, as in TypeScript. A missed case is E_RETURN.
- `x => e` and `(a, b) => e` take their parameter types from the expected function type.
- `if (c) f();`, `else g();` and loops take one statement without braces. `a ||= b`, `a &&= b`.
- An integer literal beside an `f64` is an `f64`: `x / 2`, `n === 0`.

**Errors** work as in TypeScript, with the type in the signature.
- `function f(): T throws E` returns a `Result<T, E>`. `throw e;` fails it.
- Without `throws`, a function whose own `throw` no `try` block in it catches throws what it throws: X for
  `throw new X(...)`, `string` for a string, else `Error`. A call of it propagates the same way only where the caller
  throws too.
- A call gives the `T`. A failure returns from the caller.
- `try { ... } catch (e) { ... }` handles a failure. `finally` runs when the statement ends.
- In a function that does not throw, a call that fails outside a `try` block faults (R004).
- The standard `Error` (`name`, `message`, `cause`) needs no import: `throw new Error("bad input")` in a
  `throws Error` function, and `e.message` in its catch.
- A thrown Error or string that nothing catches is printed after the fault trace.

See [LANGUAGE: Errors](language.md#errors).
```gizlang
function half(n: i64): i64 throws Error { if (n % 2 !== 0) { throw new Error(`odd: ${n}`); } return n / 2; }
function quarter(n: i64): i64 throws Error { return half(half(n)); }
```
Errors that are values are `Result<T, E>` and `Option<T>` from `gizlang:core` (`Result.ok(v)`,
`Result.err(e)`, `Option.some(v)`, `Option.none()`). `try e` unwraps `ok` or `some`. It
returns any other case from the function. The result type of the function must have that case.
```gizlang
import {Result} from "gizlang:core";

type Line = { sku: string; qty: i64; };

function find(id: string): Result<Line, string> {
    if (id === "") { return Result.err("no id"); }
    return Result.ok({ sku: id, qty: 1 });
}
export function total(id: string): Result<i64, string> { const o = try find(id); return Result.ok(o.qty); }
```
Use `opt ?? fallback`, `res.valueOr(fallback)` and `x!`. `x!` faults when
the value is absent.

**Loops**: `for (const x of v)`, `for (const i of range(0, n))`, `for (let i = 0; i < n; i++)` (a `continue` runs the
update first), `while`, `break`, `continue`. `i++`, `i--`, `++i` and `--i` are statements, not values.
`for (const [k, v] of m)` and `for (const { a } of xs)` destructure each element. A `Map` gives its `[key, value]`
entries and a `Set` its values, in insertion order. A label (`outer: for (...)`) names the loop that
`break outer;` and `continue outer;` leave. `a ??= b`, `a ||= b` and `a &&= b` assign as in TypeScript. A parameter
with a literal default and no type (`greeting = "hi"`) has the literal's type. `${x}` of an optional prints its value
or `undefined`.

**Optional values** are `Option<T>` of `gizlang:core`, with no import. `x?: T` (a field or parameter), `T | undefined`
and `T | null` are `Option<T>`.
- Where an Option is expected, `undefined` (or `null`) is none, and a `T` is some of it. So these work:
  `return undefined;`, `{ name: "a" }` without an optional field, `Options("h", 5)` without the trailing optional
  fields, and a call without an optional parameter.
- `a?.b`, `a?.[i]` and `a?.m()` give the Option of the rest of the chain. `a` runs once, in its order in the
  expression.
- `x!` is `x.unwrap()`: a fault when there is none.
- `x === undefined` and `x !== undefined` test the case and narrow `x`, as `x.kind` tests do. Where `x` is some, `x`
  reads its value (`x.value`). `x.kind`, `x.value` and the Option methods still read the Option.
- A parameter default is a literal, `[]` or `undefined`: `function f(n: i64 = 1, tag?: string)`.

**Destructuring**: `const { a, b: c } = e;` and `const [a, , c] = e;` (also with `let`) and a parameter `{ x, y }: Point`
bind fields or items; `e` runs once. A last parameter `...xs: T[]` takes the rest of the arguments as one array, and
`f(...v)` passes an array whole. `let a = 0, b = 1;` declares both. Numbers take `_` between digits: `1_000_000`.

**Interfaces** of fields (`interface User { id: i64; email?: string; }`) are record types, as `type User = { ... }`.
Interfaces of methods are the interfaces of TypeScript, with `self: Self` written first. As a type,
an interface holds any value that implements it. Arrow functions `(x: T): R => { ... }`
capture `const` values by value. A `let` that an arrow function names is shared, as in TypeScript: a change on
either side is seen by both, and each pass of a loop has its own. A block body with no `return` of a value is `void`. Function types `(x: T) => R` and `=> void` are value types:
fields, `Vec` elements, parameters and results.

A module constant that is an arrow function (`const inc = (x: i64) => x + 1;`) is a function declaration.

**Console**: `console.log(a, b)` (also `info`, `debug`, `trace`) prints its arguments joined by spaces, and
`console.error` and `console.warn` print them on standard error. An `async` function may return `Promise<void>`.

**Built-in methods** need no import, as in TypeScript. A lambda takes its parameter types from the
method, with no annotation, and compiles to a direct call.
- Arrays: `v.filter(f)`, `v.map(f)`, `v.find(f)` (an `Option`), `v.findIndex(f)` (-1 when none),
  `v.some(f)`, `v.every(f)`, `v.count(f)`, `v.reduce((acc, x) => ..., init)`, `v.includes(x)`,
  `v.indexOf(x)`, `v.at(i)` (an `Option`; -1 is the last), `v.concat(w)`, `v.slice(a, b)`, `v.push(x)`,
  `v.pop()` and `v.shift()` (an `Option`, in place), `v.join(sep)` (numbers and bools too), `v.sumBy(f)`,
  `v.findLast(f)`, `v.findLastIndex(f)`, `v.lastIndexOf(x)`, `v.flat()`, `v.flatMap(f)`, `v.toReversed()`,
  `v.with(i, x)`, `v.toSpliced(i, n, ...items)`, `v.keys()`, `v.entries()`; in place on a `let`: `v.reverse()`,
  `v.splice(i, n, ...items)` (gives the removed items), `v.unshift(...items)`, `v.fill(x)`.
- `v.toSorted(compare)` and `v.sort(compare)` (in place, on a `let`) take a TypeScript comparator, negative when `a` goes
  first (`(a, b) => a - b`, `a.name.localeCompare(b.name)`), or a bool `before(a, b)`, true when `a` goes first.
  `giz fmt` writes the former name `v.sorted(f)` as `v.toSorted(f)`.
- `new Map<K, V>()` with `set`, `get` (an `Option`), `has`, `delete`, `size`, `keys`, `values` and
  `merge`; `new Set<K>()` with `add`, `has`, `delete`, `size` and `values`. `new Map([[k, v], ...])` and
  `new Set([a, b])` start with those items, and `[...s]` spreads a Set (or a Map's values) as it spreads a Vec.
  `new Map()` takes its type arguments from the type expected. `m[k]` is `m.get(k)` and `m[k] = v` is `m.set(k, v)`.
- `Array.from(x)` makes a Vec of a Vec, a Set or a Map's values, and `Array.from({ length: n }, (_, i) => f(i))` makes
  `n` items.
- A regex literal `/a+b/u` is a gizlang:regex `Regex` (`test`, `exec`, `matchAll`, `replaceAll`, `split`), with no
  import. A pattern that does not compile faults when it runs.
- `JSON.stringify(x)` writes any value whose type is known: a record as an object of its fields (an `undefined` field
  is left out), a union's case with its `kind`, an untagged union's case as its value, a Vec as an array, a
  `Map<string, V>` as an object and `undefined` as `null`. `JSON.stringify(x, null, n)` indents. `JSON.parse(s)` reads
  the type expected (`const u: User = JSON.parse(s);`): a missing field is an error unless its type takes `undefined`,
  an unknown field is skipped, and a wrong value throws a gizlang:json `JsonError`. Where no type is expected it reads a
  `Json` value. A class instance is not written or read yet.
- An object type `{ a: T; b?: U }` is a record of those fields; two of the same fields are one type.
- `Record<K, V>` is `Map<K, V>`, and `{}` where one is expected is an empty one. Over a record type, `Partial<T>` makes
  each field an `Option`, `Readonly<T>` is `T`, and `Pick<T, "a" | "b">` and `Omit<T, "a">` keep those fields or the
  others.
- `new X(...)` calls the function `newX(...)`. `new ns.X(...)` calls the exported `newX` of the module that `ns` names.
  A `const` made by `new` changes in place as one made by a literal does.
- A method with no other parameter also reads as a property: `m.size`.
- Strings: `indexOf`, `includes`, `startsWith`, `endsWith`, `split`, `replaceAll`, `trim`,
  `padStart`, `toUpperCase`, `charAt`, `substring`, `localeCompare`, ... Numbers: `x.toFixed(digits)`.
- TypeScript's ambient functions: `Math.max(a, b, ...)`, `Math.min`, `Math.PI`, `Math.E` and the other `Math`
  functions (an integer argument is an `f64`; `Math.max` and `Math.min` of integers are integers), `Number.isInteger`,
  `Number.isNaN`, `Number.isFinite`, `String(x)`, `Object.keys(record)` (its field names), and `parseInt(s, radix)` and
  `parseFloat(s)`, which give an `Option` (`parseInt(s) ?? 0`) where TypeScript gives `NaN`. `console.log` and `${x}`
  print an `Option` as its value or `undefined`.
- Import the rest by name: `gizlang:text` (`parseI64`, a union `IntegerParse.ok(n)`/`invalid`/`overflow`,
  `parseF64`, an `Option`, and `fixed(x, digits)`) and `gizlang:math` (`floor`, `round`, `min`, `max`, `pow`, ...).

**Markup** is TSX that compiles to `Html` (`gizlang:html`). It is escaped by default.
```gizlang
import {Html, each, when} from "gizlang:html";

type Todo = { id: string; title: string; done: bool; };
function Row(t: Todo): Html { return <li class="todo" data-k={t.id}>{t.title}{when(t.done, () => <b>done</b>)}</li>; }
type ListProps = { title: string; };
function List(p: ListProps, children: Html): Html { return <section><h2>{p.title}</h2>{children}</section>; }

export function page(todos: Vec<Todo>): Html {
    return <List title="Todos"><ul>{each(todos, (t: Todo) => Row(t))}</ul></List>;
}
```
Holes take text, numbers and `Html`. A `bool` attribute is present or absent. Markup has no
spread, `&&`, `? :` or `.map`. Use `when`, `each` and `raw(trusted)`. `h.text()` is the
response body.

**Functions**: `function f(x: T): R { ... }`, and `: void` for no result. Declare a method as
`function Order.total(self: Order): i64` and call it as `o.total()`. The compiler infers effects.

**Tests** are `export function testName(): void` in a `*.test.giz` file. They assert with
`import * as Test from "gizlang:test"` (`Test.equal(a, b)`, `Test.check(c)`). `giz test FILE` runs them.

**Optional results.** `find` gives an `Option` rather than a -1 index, and `??` takes a missing
value's fallback lazily. `Task.zip(first, second)` starts two independent tasks and joins both,
returning a typed pair or Fault.

**Map optional and successful results.** `option.map((value: T) => f(value))`
returns `Option<U>` without unwrapping. `option.andThen(f)` chains a function
that returns `Option<U>`; `result.map(f)` changes only the `ok` value and
preserves `err`. The compiler dispatches `Vec.map` to its vector builtin and other `map` calls to their typed receiver
methods.

**Inferred callback results.** For `Option<T>` or `Result<T, E>`, `.map(x => f(x))`
infers both the `x: T` input and the result type from `f(x)`. Generic callback
parameters can use the same syntax after earlier call arguments establish their
types. The compiler keeps effect checking and preserves absent/error branches.

**Imported functions are receiver-callable.** An imported free function whose first argument
accepts the receiver is also a method: `x.f(a)` calls `f(x, a)`, with its signature, effects
and `mut` rules. A generic callback parameter bounded by a function type
(`F extends (value: T) => bool`) gives a lambda its parameter types, and `F` stays the lambda's
own closure type.

**Composing fallible results.** `result.mapErr(e => message(e))` converts only
an error. `result.andThen(x => next(x))` chains another `Result` with the same
error type. `try parser(input).mapErr(e => explanation(e))` propagates a mapped
error without a temporary default and a two-arm `match`.
