diff --git a/NAMESPACE b/NAMESPACE index 9cfd924..e50ce66 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -29,4 +29,5 @@ export(ts_list) export(ts_logical) export(ts_null) export(ts_numeric) +export(ts_union) export(ts_void) diff --git a/R/docs_types.R b/R/docs_types.R new file mode 100644 index 0000000..cb662ba --- /dev/null +++ b/R/docs_types.R @@ -0,0 +1,57 @@ +#' @title +#' Types in R and TypeScript +#' +#' @description +#' This document provides an overview of the main types available to +#' app developers, which includes the main types in R and their +#' TypeScript counterparts. +#' +#' @details +#' # TS objects +#' The basic object in `ts` is a `ts_object` class. This is represented by +#' input and return types, an optional default value, and a checking +#' function. +#' +#' Input types describe the `zod` schema of objects that TypeScript can pass +#' to Rserve functions. +#' +#' Return types describe the `zod` schema of objects that Rserve functions, +#' and most of these utilise the `Robj` utility types in the `rserve-ts` +#' library. The return types have additional properties added, +#' namedly `r_type` and `r_attributes`, handled by the `Robj` utility types. +#' +#' **Scalar versus array ("vector") types**: +#' In R, almost all types are vectors. In the 'rserve-js' library, +#' primitive arrays of length one are converted into scalars, which +#' leads to some issues with type checking when, for example, a return value +#' has unknown length. `which(x > 5)` is one such example. +#' +#' To solve this, we add an `n` argument to the `ts_*` functions. When `n = 1`, +#' the type takes the *scalar* form of the alue. When `n != 1`, the type takes +#' the *array* form of the value (this includes 0). Otherwise, the type +#' is the union of the scalar and array forms. +#' +#' This is the case for numbers, strings, and booleans. +#' +#' # Available types +#' +#' - `ts_boolean`: A boolean value. The array type is `Int8Array`. +#' - `ts_integer`: An integer value. The array type is `Int32Array`. +#' Javascript does not have a native integer type, +#' so scalars are represented as a number +#' (the same as `ts_numeric`). +#' - `ts_numeric`: A numeric value. The array type is `Float64Array`.* +#' - `ts_string`: A string value. The array type is `string[]`. +#' - `ts_factor`: A factor value. The array type is `(level1 | level2 | ... | levelN)[]`, and this type does not have a scalar form. +#' - `ts_list`: A list value, represented by a named object or an array. +#' - `ts_dataframe`: A data frame value, represented by a named object. +#' - `ts_null`: A null value. +#' - `ts_void`: A void value, used for specifying return types of functions +#' that do not return a value. +#' +#' +#' +#' @family type documentation +#' +#' @name type_objects +NULL diff --git a/R/function.R b/R/function.R index 41825bf..8e4d8e0 100644 --- a/R/function.R +++ b/R/function.R @@ -44,10 +44,25 @@ ts_result <- function(type, value) { #' TS function definition #' +#' @details +#' Defining functions is the core of writing Rserve apps. +#' Functions are referred to as *object capabilities* (ocaps), +#' as they are 'objects' that allow Javascript to access capabilities +#' of R with a restricted interface. Only arguments can be adjusted. +#' +#' TS functions can be defined using existing (named) or anonymous functions. +#' Anonymous functions are useful in that the arguments to the functions +#' can explicitly be defined with their types as formal arguments: +#' +#' ``` +#' ts_function(function(x = ts_integer(), y = ts_string()) { ... }) +#' ``` +#' #' @param f an R function #' @param ... argument definitions (only required if f does not specify these in its formals) #' @param result return type (ignored if overloads are provided) #' @export +#' @md ts_function <- function(f, ..., result = ts_void()) { args <- list(...) if (!is.null(result) && !is_ts_object(result)) { diff --git a/R/types.R b/R/types.R index e3f7a2c..073feba 100644 --- a/R/types.R +++ b/R/types.R @@ -1,6 +1,7 @@ #' Typed object #' -#' This is the base type for all typed objects. It is not meant to be used directly. +#' This is the base type for all typed objects, and can be used to define +#' custom types. #' #' @param input_type The type of the object that Typescript expect to send to R. #' @param return_type The type of the object that Typescript expects to recieve from R. @@ -111,7 +112,14 @@ check_type.ts_function <- function(type, x) { ) } +#' Union type +#' +#' Create a union of types. Currently this only accepts schemas as strings. +#' @param ... Types to merge +#' @export +#' @md ts_union <- function(...) sprintf("z.union([%s])", paste(..., sep = ", ")) + ts_array <- function(type = c("z.number()", "z.boolean()", "z.string()")) { if (type == "z.number()") { return("z.instanceof(Float64Array)") diff --git a/_pkgdown.yml b/_pkgdown.yml index abccc4c..eb3e401 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,7 +1,7 @@ url: http://tomelliott.co.nz/ts/ template: bootstrap: 5 - bootswatch: cosmo + bootswatch: simplex reference: - title: Building apps @@ -14,6 +14,7 @@ reference: - title: Types desc: Type helper functions for defining argument and return types. - contents: + - type_objects - ts_logical - ts_integer - ts_numeric @@ -24,3 +25,4 @@ reference: - ts_null - ts_void - ts_object + - ts_union diff --git a/man/ts_function.Rd b/man/ts_function.Rd index 2daaba5..cfc890f 100644 --- a/man/ts_function.Rd +++ b/man/ts_function.Rd @@ -16,3 +16,16 @@ ts_function(f, ..., result = ts_void()) \description{ TS function definition } +\details{ +Defining functions is the core of writing Rserve apps. +Functions are referred to as \emph{object capabilities} (ocaps), +as they are 'objects' that allow Javascript to access capabilities +of R with a restricted interface. Only arguments can be adjusted. + +TS functions can be defined using existing (named) or anonymous functions. +Anonymous functions are useful in that the arguments to the functions +can explicitly be defined with their types as formal arguments: + +\if{html}{\out{