Gradual Typing
Infr is a gradually typed superset of R. This means you can add types incrementally — no annotations means no errors, and each annotation you add gives you more safety.
How it works
In a gradually typed system, unannotated code is treated as having type any — it's not checked but it's not an error either. As you add annotations, Infr checks more of your code:
# No annotations — Infr treats everything as `any`, no errors
x <- 5
y <- "hello"
z <- x + y # No error from Infr (R will error at runtime)
# With annotations — Infr catches the bug
const x: numeric <- 5
const y: character <- "hello"
const z <- x + y
# Error [infr]: Cannot apply `+` to numeric and character
Type inference
You don't need to annotate everything. Infr infers types from:
- Literals:
5isnumeric,"hello"ischaracter,TRUEislogical - Operators:
x + 1isnumericifxisnumeric - Known functions:
paste()always returnscharacter,nrow()returnsinteger - Flow: types propagate through variable assignments
const x <- 5 # inferred: numeric
const y <- "hello" # inferred: character
const z <- x + 10 # inferred: numeric
const w <- x > 3 # inferred: logical
const msg <- paste(y, "world") # inferred: character
The any type
When Infr can't determine a type, it falls back to any. You can also use any explicitly as an escape hatch:
const result: any <- eval(parse(text = some_string))
# No type checking on `result`
Why gradual typing?
R has a massive ecosystem of existing code. Requiring full type annotations upfront would make Infr unusable for real projects. Gradual typing lets you:
- Start with zero changes to existing code
- Add types where they provide the most value (function signatures, data frames)
- Increase strictness over time as your codebase matures
This approach is proven — TypeScript followed the same path for JavaScript, and mypy/Pyright did the same for Python.