Skip to content

Language boundaries

Supported composition, current limitations, and alternatives.

Updated View as Markdown

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.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close