When it comes to checking the data type of a variable, it depends on what specific thing you are looking for in a variable, because you have many options to choose from. Each option tells you a different but important story.
There are four main core functions to check data types in R:
- typeof(): It returns the underlying storage type. It can be useful to understand low-level storage.
- class(): It returns an object’s class (S3 / S4), which dictates how functions will interact with it.
- mode(): It is similar to typeof() but less precise.
- storage.mode(): It uses older terminology such as, “double” instead of “numeric”. It is synonymous with the typeof() function.
By checking the type, we won’t pass a string to a numeric algorithm.
Let’s take a simple code example:
vec <- 19:21
typeof(vec)
# [1] "integer"
class(vec)
# [1] "integer"
mode(vec)
# [1] "numeric"
storage.mode(vec)
# [1] "integer"
As you can see, only the mode() method returns less precise output, which is “numeric” instead of an “integer.”
Type Predicates: is.*() Functions
If you are working with an Atomic vector, there is an efficient way to check its data type.
For example, R’s simplest containers hold one of six basic types:
- For logical, use is.logical() method that returns a boolean value (TRUE or FALSE). If it finds a logical value, it returns TRUE, else FALSE.
- For integer checking, use the is.integer() method. It returns a boolean value (TRUE or FALSE). If it finds an integer value, it returns TRUE, else FALSE. It also returns FALSE for factors or dates.
- For double, use is.double() method. If it finds a double (float) value, it returns TRUE, otherwise FALSE.
- For complex, use is.complex() method. If it finds a complex value, it returns TRUE, otherwise FALSE.
- For character, use is.character() method. If it finds a character value, it returns TRUE, otherwise FALSE.
- For raw, use is.raw() method. If it finds a raw value, it returns TRUE, otherwise FALSE.
# --- Logical ---
logical_var <- TRUE
typeof(logical_var)
# [1] "logical"
is.logical(logical_var)
# [1] TRUE
# --- Integer ---
integer_var <- 123L
typeof(integer_var)
# [1] "integer"
is.integer(integer_var)
# [1] TRUE
is.numeric(integer_var) # Integers are also numeric
# [1] TRUE
# --- Double ---
double_var <- 3.14159
typeof(double_var)
# [1] "double"
is.double(double_var)
# [1] TRUE
is.numeric(double_var)
# [1] TRUE
double_var2 <- 100 # Default is double
typeof(double_var2)
# [1] "double"
is.double(double_var2)
# [1] TRUE
is.integer(double_var2) # Check if it's integer (False)
# [1] FALSE
# --- Complex ---
complex_var <- 2 + 3i
typeof(complex_var)
# [1] "complex"
is.complex(complex_var)
# [1] TRUE
is.numeric(complex_var) # Complex are not numeric
# [1] FALSE
# --- Character ---
character_var <- "Hello R!"
typeof(character_var)
# [1] "character"
is.character(character_var)
# [1] TRUE
# --- Raw ---
raw_var <- as.raw(48) # ASCII for '0'
typeof(raw_var)
# [1] "raw"
is.raw(raw_var)
# [1] TRUE
raw_var2 <- charToRaw("A") # Hex for 'A'
typeof(raw_var2)
# [1] "raw"
is.raw(raw_var2)
# [1] TRUE
There are other functions in these predicates that we will discuss later in this article.
Factors
By default, factors are stored internally as integers, but if you use is.integer(), it returns FALSE.
fact <- factor(c("k", "b"))
is.integer(fact)
# [1] FALSE
typeof(fact)
# [1] "integer"
Now, if you check its class, it will return a factor like this:
fact <- factor(c("k", "b"))
class(fact)
# [1] "factor"
To check if an input object is a factor, always use the is.factor(x) or inherits(x, “factor”).
fact <- factor(c("k", "b"))
is.factor(fact)
# [1] TRUE
Dates
Dates are stored as a double, but it has a class of “Date”. So, if you use is.numeric() function on it, it returns FALSE.
dt <- Sys.Date()
class(dt)
# [1] "Date"
typeof(dt)
# [1] "double" (days since 1970-01-01)
Lists, Data Frames, Matrices & Arrays
To check for a type list, always use the is.list() method.
main_list <- list(a = 1, b = "z", c = Sys.Date())
typeof(main_list)
# "list"
is.list(main_list)
# TRUE
To check for a type data frame, always use the is.data.frame() method. It has a class called “data.frame“.
df <- data.frame(x = 1:3, y = c("a", "b", "c"))
class(df)
# [1] "data.frame"
is.data.frame(df)
# [1] TRUE
typeof(df)
# [1] "list"
To check a Matrix / Array, you should use the is.matrix() / is.array() methods.
mat <- matrix(1:6, nrow = 2)
is.matrix(mat)
# [1] TRUE
is.array(mat)
# [1] TRUE
typeof(mat)
# [1] "integer"
class(mat)
# [1] "matrix" "array"
dim(mat)
# [1] 2 3
NA and NULL Types
You can interpret NA as missing values. NA can be logical, integer (NA_integer_), or double (NA_real_).
typeof(NA)
# [1] "logical"
typeof(NA_integer_)
# [1] "integer"
typeof(NA_real_)
# [1] "double"
typeof(NA_character_)
# [1] "character"
If you check a type for a NULL value, the typeof() function will return NULL.
typeof(NULL)
# [1] NULL
You can also use the is.null() function to check if an input value is NULL.
is.null(NULL)
# [1] TRUE
That’s all!

Krunal Lathiya is a seasoned Computer Science expert with over eight years in the tech industry. He boasts deep knowledge in Data Science and Machine Learning. Versed in Python, JavaScript, PHP, R, and Golang. Skilled in frameworks like Angular and React and platforms such as Node.js. His expertise spans both front-end and back-end development. His proficiency in the Python language stands as a testament to his versatility and commitment to the craft.