Create your first TypR package
This tutorial walks you through creating a complete R package with TypR — from an empty folder to an installable package with types, tests, and documentation.
Duration: 15–20 minutes.
This is a tutorial. It teaches you by doing. For the full details on every construct used here, follow the links to the reference.
What you will build
A small package called tempscale that converts temperatures between Celsius,
Fahrenheit, and Kelvin. By the end you will have:
- A
TypR/folder with typed source code - Generated R code in
R/ - Inline tests extracted into testthat
- Roxygen2 documentation from type annotations
- A package that installs and checks cleanly
Prerequisites
- R (≥ 4.1) and devtools installed
- The
typrcompiler — see the installation guide - A terminal and a text editor
Step 1: Scaffold the package
Create a new directory and initialize a minimal R package:
mkdir tempscale
cd tempscale
Rscript -e 'devtools::create(".")'
This gives you DESCRIPTION, NAMESPACE, and an R/ folder. Now add the
TypR folder:
mkdir TypR
Your package should look like this:
tempscale/
DESCRIPTION
NAMESPACE
R/ # generated code will go here
TypR/ # your typed source code
Step 2: Write typed source code
Create TypR/main.ty with a type definition, a constructor, and two functions:
# main.ty — entry point of the package
type Temp <- list {
value: num,
unit: char
};
let new_temp <- fn(value: num, unit: char): Temp {
list(value = value, unit = unit)
};
let to_celsius <- fn(t: Temp): num {
match t$unit {
"C" => t$value,
"F" => (t$value - 32.0) * 5.0 / 9.0,
"K" => t$value - 273.15,
_ => { print("Unknown unit"); t$value }
}
};
@pub let to_fahrenheit <- fn(t: Temp): num {
to_celsius(t) * 9.0 / 5.0 + 32.0
};
A few things to notice:
Tempis a record type — a named structure with typed fields.matchgives you exhaustive pattern matching on strings.@pubmarksto_fahrenheitas public — it will be exported in the generated NAMESPACE.new_tempandto_celsiusare package-internal by default.
Step 3: Add inline tests
Add a Test block at the bottom of TypR/main.ty:
Test {
test_that("to_celsius converts Fahrenheit", {
let f <- new_temp(212.0, "F");
expect_equal(to_celsius(f), 100.0, tolerance = 1e-10);
})
test_that("to_celsius converts Kelvin", {
let k <- new_temp(373.15, "K");
expect_equal(to_celsius(k), 100.0, tolerance = 1e-10);
})
test_that("to_fahrenheit converts Celsius", {
let c <- new_temp(100.0, "C");
expect_equal(to_fahrenheit(c), 212.0, tolerance = 1e-10);
})
}
During transpilation, this block is extracted into a standard
tests/testthat/test-main.R file. To R, devtools, and testthat, it is just
regular test code.
Step 4: Build
Run the compiler from the package root:
typr build
TypR transpiles TypR/main.ty into R/ files:
R/
a_std.R # generated helpers
b_generic_functions.R # generated helpers
c_types.R # generated type definitions (Temp, new_temp, ...)
d_main.R # transpiled main.ty
The naming convention (a_, b_, c_, d_) ensures correct load order.
Step 5: Test
Run the tests as you would for any R package:
devtools::test()
You should see all three tests pass. The test code was generated from the
Test block — you never had to write tests/testthat/ by hand.
Step 6: Document
The @pub keyword on to_fahrenheit generates a roxygen2 @export directive.
Type annotations are turned into @param and @return tags. Run:
devtools::document()
This populates man/ with .Rd files and updates NAMESPACE.
Step 7: Install and check
devtools::install()
devtools::check()
The package installs and passes R CMD check. CRAN, pkgdown, and
devtools::check() all see regular R code — TypR is invisible at this stage.
Where you are now
You have built a complete R package using TypR:
- Types —
Tempis a record type with named, typed fields. - Pattern matching —
matchon unit strings replaces if/else chains. - Tests — inline
Testblocks that extract into testthat. - Documentation —
@pubgenerates roxygen2 exports. - Standard R — the generated code is plain R that any R tool understands.
Where to go next
- Migrate an existing R package — add TypR to a package you already have
- Model data with TypR types — records, unions, and dataframes in depth
- How-To: Build, test & document — the full development workflow
- Reference: Records & Constructors — construction, spread, and named embedding