Skip to content
LogoLogo

Type System

Result returns, requirements, optionals, and boundary precision

Status: the Result failure model, inferred requirements, and built-in Optional model are locked. Optional interop details and the emitted TypeScript representation of requirements remain open.

Gradual Foundation

VibeLang extends TypeScript's gradual type system. Existing TypeScript escape hatches remain available on the TypeScript target and MAY be restricted by lint policy rather than the language.

Recoverable errors and requirements add precision without requiring a separate globally strict mode or an Effect interpreter.

Function Type

A VibeLang function has:

  • an ordinary return type, which is Result<A, E> when the function can fail
  • an inferred set R of nominal capability requirements

Functions MUST remain eager. A Result is an ordinary returned value used only by fallible functions; it is not a universal wrapper around all computation.

Fallibility Inference

For a function with a body and no return annotation, the compiler MUST infer:

  • A from successful return paths
  • E from reachable Error throws, Result propagation, returned Results, and foreign boundaries
  • R from Capability.context() calls and transitive callees

A function with non-empty E MUST have inferred return type Result<A, E>. An async function with non-empty E MUST have inferred return type Promise<Result<A, E>>.

Plain success returns and Error throws MUST be compiler-lifted as defined by Failure Semantics.

If an explicit return annotation cannot represent a reachable recoverable Error, the compiler MUST reject the function rather than permit an untyped exception path.

Public Boundaries

Public contracts MUST use ordinary generic type syntax:

declare function loadUser(id: string): Result<User, NotFound | Unavailable>
 
declare function fetchUser(
  id: string,
): Promise<Result<User, NotFound | Unavailable>>

VibeLang MUST NOT add throws E, !T, or another failure-annotation grammar.

The R set MUST be inferred from compiler-recognized context access and preserved in exported declarations. Its emitted TypeScript representation remains open.

Result Composition

Result types MUST compose without nested Result<Result<A, E1>, E2> values when a compatible Result is returned or produced by andThen.

Transformations MUST union error types when they can introduce additional errors. Exhaustive recovery MAY remove handled members from E.

An ignored Result MUST be a compile error.

Foreign Boundaries

Using a runtime value from a TypeScript or JavaScript module adds the TypeScript requirement. A potentially throwing call MUST also return a Result whose error includes UnhandledException unless trusted metadata or an adapter supplies a more precise Error type.

Type-only imports add neither runtime requirement.

Async Values

An infallible async function returns Promise<A>. A fallible async function returns Promise<Result<A, E>>.

declare function loadUser(
  id: string,
): Promise<Result<User, Unavailable>>

Awaiting the call removes only the Promise layer. The resulting value remains Result<User, Unavailable> until it is matched, transformed, returned, or unwrapped.

Promise instance chaining is unavailable in authored .vibe; .then, .catch, and .finally MUST be rejected.

Optional

VibeLang MUST provide a built-in Optional<T> value type using ordinary generic and method-call syntax.

An Optional-returning function MUST compiler-lift:

  • return value to the present variant
  • return null or return undefined to the absent variant
  • an existing compatible Optional without nesting

The ordinary authoring API MUST NOT require Optional.some(...) or Optional.none().

Optional values MUST provide operations equivalent in purpose to:

isSome  isNone  match  map  andThen  filter
tap     unwrap  unwrapOr  toResult  toNullable  all

The earlier ?T, payload-capture, orelse, and .? grammar MUST NOT be part of the initial language.

Optional absence MUST remain distinct from a Result error. Optional<T> MAY convert explicitly to Result<T, E> through toResult(error).

When both layers are declared, lifting MUST follow the written type from outside in. For Result<Optional<A>, E>, a plain A becomes a successful present value, a nullish return becomes a successful absent value, an existing Optional becomes the Result success, and an Error throw becomes the Result error. Existing compatible Result values MUST still pass through without nesting.

Optional.fromNullable(...) MUST explicitly adapt T | null | undefined, and optional.toNullable() MUST adapt back to T | null. Optional properties and parameters MUST keep their TypeScript meaning. Nested optional normalization and any additional implicit conversions remain open.

Reification

Ordinary types MAY be consumed as comptime values. Comptime code MAY derive validators, codecs, equality, hashing, schemas, and generated types.

There MUST NOT be a separate runtime type declaration modifier.

At durable boundaries, Result and Optional variants and all enclosed values MUST have compiler-known durable codecs or explicit user-supplied codecs.