Skip to main content

Escape Hatches

This page covers the mechanisms for dropping out of TypR's type system to write raw R or JavaScript code.

extern — typed R escape

extern (x: int, y: char) -> char r#"paste0(x, y)"#;   # raw R body, typed input/output

extern keeps a TypR-verified signature around an opaque R body. The compiler checks the types; the R code itself is emitted verbatim.


Untyped R functions

function(x, y) { x + y }     # raw R function (RFunction), body captured as-is

Any function(...) expression is captured as an untyped R function — no type checking on the body.


R { } blocks — raw R values

R {
df |>
dplyr::filter(x > 1) |>
dplyr::mutate(z = y + 1)
}

R { ... } captures its body verbatim (balanced braces, like function(...)), and transpiles to a plain R block { ... } — which already evaluates to the value of its last instruction, so no wrapper or call is emitted.

This is the preferred form for idiomatic R that is difficult to type (pipes %>%/|>, dplyr NSE, formulas ~, etc.) when you just want a value without worrying about the type system.


JS { } blocks

JS { /* ... */ }               # raw JavaScript block (JS target)

For targeting JavaScript output (when TypR compiles to JS).


Class(...) — R class denotation

Class("data.frame", "tbl")    # denotes an existing R class (RClass)

Used to name existing R classes in the type system without constructing them.


@{ ... }@ — vectorial blocks

@{ 1 + x * 2 }@

Vectorial blocks are re-parsed as a sequence of TypR elements (literals, calls, variables) — not arbitrary R. This is different from R { ... }, which captures arbitrary R code.


Comparison

FormType-checked?Use case
externsignature yes, body noTyped interop with existing R functions
function(...)noUntyped R functions
R { }noIdiomatic R values (pipes, NSE, formulas)
JS { }noJavaScript target
@{ }@partially (TypR elements only)Lightweight vectorial expressions
Class(...)naming onlyReferencing existing R classes