The removed constructs below are unwritable in Hem source. Removed words stay reserved as ordinary identifiers. null and undefined are admitted inside type expressions to preserve exact TypeScript contracts; their value literals remain removed.
Removed, with replacements
| Construct | Status | Replacement |
|---|---|---|
const |
Removed | Write let: Hem’s let is TypeScript’s const |
var, function, switch, loose == |
Removed | let, arrows, match, strict == |
Truthiness, null and undefined literals |
Removed | Boolean conditions, ??, None, ?T |
any |
Demoted on contact | unknown plus narrowing, cast inserted automatically |
enum, interface, namespace, declaration merging |
Removed | Variants, type, modules |
this outside classes, arguments |
Removed | Closures, rest parameters |
Key-iterating for..in, C-style for, do..while, labels |
Removed | Value for..in, ranges, while |
++, --, the comma operator |
Removed | +=, statements |
| Unchecked indexing | Removed | xs[i] is ?T |
| Statement-only exception handling | Demoted | Postfix catch everywhere; try remains as a residual form |
T | null and T | undefined are exact type contracts; ?T admits both sentinels. Use contextual None in value position. This type syntax does not enable unchecked assertions or authored predicate promises.
Operator restrictions
== compiles to ===. Coercing equality is not expressible. The single exception is == and != against None, which emit == null and != null so that one evaluation eliminates both nullish members.
Conditions, !, &&, and || accept boolean operands only. A non-boolean condition reports HEM2002.
Binary + and += are arithmetic only: both operands number, or both bigint. Operands cannot be strings or mixed numeric types. Unary + requires an operand that is already number, rather than performing runtime conversion like Number(x). All three cases report HEM2021. String concatenation has one spelling, a template literal.
Words that are not removed
type and error are contextual keywords. They open a declaration only at the start of a statement with an identifier following, as in type Id = string or error NotFound({ id: string }).
Everywhere else they are ordinary identifiers. All of the following are plain code:
let error = validate(input)
let handler = (type: string) => type
let { type } = event
let tag = event.typebrand is contextual in one position, immediately after a type declaration’s =. deriving is active only in a deriving Eq clause on a variant or error declaration.
Statement results must be used
A statement whose only outcome is to compute and discard a value reports HEM2018. Two shapes are refused.
The syntactic tier covers statements that cannot have any effect: a bare name, a field or index access, a literal, or a comparison.
The type-directed tier covers a call or await whose checked result is a carrier by declaration origin: canonical standard Option or Result, an Effect, a Promise or PromiseLike, or a boxed Option or Result from the Effect transport. Canonical carriers remain must-use when Effect is disabled.
Ordinary side-effecting calls stay legal because their results are not carriers, including array.push, map.set, and console.log. A ?T is not a carrier.
The deliberate discard is let _ = expression, which emits void (expression); and leaves no unused TypeScript binding.
Emit guarantees
Emitted TypeScript contains no enums, namespaces, or parameter properties. Output runs unmodified under Node type stripping and TypeScript’s erasableSyntaxOnly.
Normative source
Specification 0.2, §15 (removed constructs), §6 (operators and must-use), §2 (lexical structure).