If you have written TypeScript, the type annotations will feel familiar — but they are not erased: they compile to layouts and to native code. And the surprises JavaScript keeps are all gone: one equality, no coercion, no undefined, no this that changes meaning by call site.
| Concept | JavaScript | Keal |
|---|---|---|
| Binding | const x = 1 | val x = 1 |
| Mutable | let x = 1 | var x = 1 |
| Function | function add(a, b) { return a + b } | func add(a: Int, b: Int): Int { a + b } |
| Arrow | xs.map(x => x * 2) | xs.map({ it * 2 }) |
| Array | [1, 2] | [1, 2] |
| Object / Map | new Map([["a", 1]]) | {"a": 1} |
| Template literal | `hello ${name}` | "hello ${name}" |
| Null check | x ?? "d" | x ?: "d" |
| Optional chain | x?.length | x?.length |
| Class | class C { constructor(n) { } } | class C(var n: Int) |
| Promise | await f() | actors: spawn / send / run |
== compares values of the same type; there is no === because there is nothing to distinguish it from. "1" + 1 does not silently become a string of digits — although "n = " + n is allowed and renders the value.
One absent value, in the type or not at all. A missing map key gives null, and the checker makes you handle it.
Inside a method, this is the instance. It cannot be rebound, lost in a callback, or shadowed by an arrow function.
There is no bundler and no runtime to ship: keal build emits C11 and hands it to a C compiler.