UI Drafter

Types in plain JavaScript

by Eric Fortis
Typed languages are fine, as far as they go. But unless the type system is Turing complete, type correctness cannot imply program correctness. — Uncle Bob

Let’s explore how we can validate types and precise constraints with convenient error messages in JavaScript. For example:

function updateCardDecimals(cardId, decimals) {
  setCard(cardId, CF.decimals, decimals)

That function is for formatting UI Drafter’s formulas.

Update Decimals of the Formula Total


Let’s ensure that cardId is a validly formatted string, and assert the card exists in the collection.

function isCard(cardId) {
  if (!/^[a-z]+$/i.test(cardId) ||
      !Object.hasOwn(cardsCollection, cardId))
    throw new CardNotFound(cardId)

class CardNotFound extends ReferenceError {}


In addition to the integer check, we can verify that the value is in the allowed numeric range.

function isValidDecimal(value) {
  if (!Number.isInteger(value) ||
      value < 0 || 
      value > MAX_FRACTION_DIGITS)
    throw RangeError(`Invalid Decimal "${value}"`)

BTW, the JavaScript Error Types:

EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError, AggregateError

Server Side Example

In the following function we’ll send a Bad Request HTML response when the number of fields in the payload, or their names, don’t match the expectation. Also, we’ll examine the values beyond their data type.

const AuthError = 1
const ValidationError = 2

async function resetPasswordPost(request, response) {
  try {
    const body = await jsonBody(request)

    if (!(
      && Object.keys(body).length === 3
      && isPassword(body.password)
      && isId(body.userId)
      && isId(body.token)
      throw ValidationError

    if (!await passwordResetTokenExists(body.token, body.userId))
      throw AuthError

    // …

  catch (error) {
    switch (error) {
      case AuthError:       sendUnauthorized(response); break;
      case ValidationError: sendBadRequest(response);   break;
      default:              sendInternalServerError(response);
function isId(value) {
    return check(value, String)
    && value.length === StandardIdCharLength
    && /^[\w-]*$/.test(value)

Open Source

Check out this library: type-check

check('a', String)
check(100, Number)
check(new Int8Array([1, 2, 3]), Int8Array)

Sponsored by: