Use this page to check whether a language form is supported and find an alternative when it is not. The linked references give exact syntax and diagnostics.
Supported composition
Structural-record patterns support whole and nested as aliases and record
alternatives at arm and field level. Alternatives bind the same names with
compatible checked types. The first complete match supplies the bindings;
a false guard advances to the next arm without retrying alternatives.
Control-flow values work in the ordinary and optional-call argument positions
listed in control flow. Optional short-circuiting
skips argument work. Synchronous postfix catch works in supported value
positions, including nested calls. Effect catch also supports expression use.
For exact pattern restrictions, see pattern matching. Method-tagged templates and arbitrary statement-block positions are not generally supported. Keep branches explicit and bind intermediate values in unsupported positions.
Unsupported forms and alternatives
| Unsupported form | Alternative |
|---|---|
Entirely unannotated None match inference |
Supply a contextual type so Hem can select the nullish sentinel. |
| Class accessors, decorators, access modifiers, or declaration-only members | Use the supported class subset. |
| Arbitrary class extractors | Use instanceof and explicit property access. |
| First-class ranges | Use loop-head ranges in for and ordinary iterables elsewhere. |
| Destructuring a range-loop binder | A range produces one number per iteration: write for index in start..end. Destructure values from an ordinary iterable instead. |
Partially annotated awaited and groups, including carrier groups |
Annotate every member or omit every annotation. Keep the group to preserve concurrent evaluation and first-rejection behavior. |
Mutation, annotations, or else on a wildcard discard |
Use unmodified let _ = value to discard. Bind a named value when you need annotations, mutation, or recovery. |
| Catch-arm guards | Use explicit branching and rethrowing; unmatched failures must still propagate. |
| Group-level binding recovery | Recover individual values. |
Direct .hem imports across tsconfig boundaries |
Use emitted modules and declarations at package boundaries. |
| Index presence inferred from a bounds check | Keep explicit nullish handling. |
Contextual cancellation signal |
Use explicit cancellation-aware Effect lifts, with API-specific cleanup. |
| Custom discriminants on Hem-authored variants | Keep _tag, or use imported TypeScript unions, which can have other discriminant fields. |
| Labelled positional arguments | Use ordinary trailing options objects. |
| Native dprint integration | Use Hem’s formatter. |
| Static cyclic-equality detection | Use derived equality for acyclic values and a custom comparator for intentional cycles. |
Other boundaries
Runtime debugging uses separate version-3 source maps in generated siblings. Node can consume them with --enable-source-maps; Vite composes the TypeScript/JSX and bundle maps. A plain tsc JavaScript build needs explicit map composition. Generated scaffolding maps to the nearest authored construct rather than pretending every generated operation exists in Hem. See runtime debugging.
Hem functions are arrows and modules are ESM. Constructor parameter properties are excluded by the erasable-output contract; use explicit fields and constructor assignments. Unsupported source forms can remain in separately compiled TypeScript modules, subject to the same foreign trust boundaries as other imports. Moving a refused unsafe operation into a shim does not make it checked.
Runtime schemas are explicit library values, not automatic deriving Schema
output. Retry, scheduling, Layer architecture, fiber lifetime, and cancellation
policy remain explicit Effect or library code.
Migration acceptance is whole-file. Manually migrate or retain a TypeScript module when a file cannot be accepted; partial output is not a successful migration.