Code Monkey home page Code Monkey logo

access's Introduction

Access

codecov

Get deeply nested properties from unknown shapes with at-runtime type safety.

Access allows you to get values in unknown or any types and be assured you will get the correct type out. If the value is missing, undefined, or the incorrect type, the given fallback is returned instead. This is achieved with at-runtime type checking. A global callback can also be registered to be called anytime a fallback is returned.

Installation

yarn
yarn add access
npm
npm install access

Example

import { getString, getNumber } from 'access';

const apiResponse: unknown = {
  data: {
    user: {
      address: {
        state: 'MA',
      },
    },
  },
};

getString(apiResponse, x => x.data.user.address.state, 'state not found'); // "MA"
getString(apiResponse, x => x.missing.key, 'fallback'); // fallback
getNumber(apiResponse, x => x.data.user.address.state, 999); // 999

API

getString

getString<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType), fallback: string, callback?: (e: Error) => void): string

getNumber

getNumber<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: number, callback?: (e: Error) => void): number

getBoolean

getBoolean<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: boolean, callback?: (e: Error) => void): boolean

getStringArray

getStringArray<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: string[], callback?: (e: Error) => void): string[]

getNumberArray

getNumberArray<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: number[], callback?: (e: Error) => void): number[]

getBooleanArray

getBooleanArray<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: boolean[], callback?: (e: Error) => void): boolean[]

getStringMap

getStringMap<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: { [key: string]: string }, callback?: (e: Error) => void): { [key: string]: string }

getNumberMap

getNumberMap<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: { [key: string]: number }, callback?: (e: Error) => void): { [key: string]: number }

getBooleanMap

getBooleanMap<ObjectType, ReturnType>(obj: ObjectType, accessor: (obj: ObjectType) => ReturnType, fallback: { [key: string]: boolean }, callback?: (e: Error) => void): { [key: string]: boolean }

Configuration

A callback can be registered with the default access export. This callback will be called anytime a fallback is returned.

A typical usecase for this is to send a message to some error tracking software signaling that a CMS or some other remote server is no longer returning data in a shape that we expected. See the example below:

Configuration Example

getter.ts

import access from 'access';

const {
  getString,
  getNumber,
  getBoolean,
  getStringArray,
  getNumberArray,
  getBooleanArray,
  getStringMap,
  getNumberArray,
  getBooleanMap,
} = access(error => {
  ErrorTracker.send('ui.fallback.returned', error);
});

export { getString, getNumber, getBoolean, getStringArray, getNumberArray, getBooleanArray, getStringMap, getNumberArray, getBooleanMap };

example.ts

import { getString, getNumber } from './getter.ts';

const apiResponse: unknown = {
  data: {
    players: {
      1: {
        userName: 'player one',
      },
    },
  },
};

getString(apiResponse, x => x.missing.key, 'fallback text'); // "fallback text"
// error ('ui.fallback.returned', PropertyMissingException...) was sent to ErrorTracker

Related Projects

ts-get and idx share the same goals and API as this one. The biggest difference is that this library works against unknown types, whereas the others require the accessed object to be explicitly typed with optional types. Neither library does runtime checking to prevent against type mismatches either.

FAQ

Why not use a generic type signature?

The library was originally implemented as one generic get function. It looked something like:

function access<ObjectType, ReturnType extends number>(
  obj: ObjectType,
  accessor: (obj: ObjectType) => ReturnType,
  fallback: ReturnType,
): number;
function access<ObjectType, ReturnType extends string>(
  obj: ObjectType,
  accessor: (obj: ObjectType) => ReturnType,
  fallback: ReturnType,
): string;
function access<ObjectType, ReturnType extends boolean>(
  obj: ObjectType,
  accessor: (obj: ObjectType) => ReturnType,
  fallback: ReturnType,
): boolean;
function access<ObjectType, ReturnType extends number[]>(
  obj: ObjectType,
  accessor: (obj: ObjectType) => ReturnType,
  fallback: ReturnType,
): number[];
function access<ObjectType, ReturnType extends string[]>(
  obj: ObjectType,
  accessor: (obj: ObjectType) => ReturnType,
  fallback: ReturnType,
): string[];
function access<ObjectType, ReturnType extends boolean[]>(
  obj: ObjectType,
  accessor: (obj: ObjectType) => ReturnType,
  fallback: ReturnType,
): boolean[];
function access(object, accessorFn, fallback, fallbackCallback) {
  try {
    const result = accessor(object);
    if (isNumber(fallback) && isNumber(result)) return result;
    if (isString(fallback) && isString(result)) return result;
    if (isBoolean(fallback) && isBoolean(result)) return result;
    if (isNumberArray(fallback) && isNumberArray(result)) return result;
    if (isStringArray(fallback) && isStringArray(result)) return result;
    if (isBooleanArray(fallback) && isBooleanArray(result)) return result;
  } catch (e) {
    return fallback;
  }
}

This generic implementation โ€” while having a much smaller surface area โ€” had large performance implications, especially when dealing with arrays and maps. Due to the nature of the runtime typechecking, the fallback and return value had to be checked against all possible return types to be able to infer which type to return. Therefor multiple (more specific) methods were chosen over this simpler syntax.

access's People

Contributors

conordavidson avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.