Skip to main content

Type Annotations

Type annotations tell Infr what types you expect. They are optional — Infr infers types wherever possible — but annotations help with documentation and catch errors at function boundaries.

Variable annotations

Add a type after the variable name with ::

const x: numeric <- 5
let name: character <- "Alice"
const flag: logical <- TRUE
const items: list <- list(1, "a", TRUE)

Function signatures

Annotate parameters with : and return types with ->:

add <- function(x: numeric, y: numeric) -> numeric {
x + y
}

greet <- function(name: character, excited: logical = FALSE) -> character {
if (excited) {
paste0("Hello, ", name, "!")
} else {
paste("Hello", name)
}
}

When annotations are present, Infr checks:

  • Arguments are called with correct types
  • The return value matches the declared return type
  • Default values match the parameter type

When annotations are absent, the function is unchecked (gradual typing).

Data frame types

Data frames get first-class typed support:

const df: data.frame<{
id: integer,
name: character,
score: numeric
}> <- data.frame(
id = 1:3L,
name = c("Alice", "Bob", "Charlie"),
score = c(95.5, 87.0, 92.3)
)

df$score # numeric
df$name # character
df$nonexistent # Error [infr]: Column `nonexistent` does not exist

Named list types

const person: list<{name: character, age: numeric}> <- list(name = "Alice", age = 30)

person$name # character
person$age # numeric
person$email # Error [infr]: Field `email` does not exist on list<{name, age}>

Nullable types

Use ? to indicate a type that can be NULL:

find_user <- function(id: integer) -> character? {
if (id > 100) NULL
else "Alice"
}

See the Types Reference for the complete type system.

Function types

const transformer: (numeric) -> numeric <- function(x: numeric) -> numeric { x * 2 }

apply_fn <- function(f: (numeric) -> numeric, x: numeric) -> numeric {
f(x)
}

Type aliases

Create named types to reduce repetition:

type Score = numeric
type Person = list<{name: character, age: numeric}>

add_scores <- function(a: Score, b: Score) -> Score { a + b }
const alice: Person <- list(name = "Alice", age = 30)

See the Types Reference for full details.

Literal types

Use exact values as types:

type Direction = "north" | "south" | "east" | "west"
type Dice = 1 | 2 | 3 | 4 | 5 | 6

See the Types Reference for full details.

Union types

const value: numeric | character <- if (flag) 42 else "hello"

if (is.numeric(value)) {
value + 1 # OK — narrowed to numeric
} else {
nchar(value) # OK — narrowed to character
}