npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@baublet/ts-object-helpers

v3.0.2

Published

Useful helpers for working with objects and their properties in TypeScript in a type safe manner

Downloads

31

Readme

TypeScript Object Access Helpers Main Branch Status

Solves the problem of type-safe, deep-object access (or partial access) that is made possible with recent TypeScript language features.

import { get } from "@baublet/ts-object-helpers";

const show = {
  name: "The Fresh Prince",
  characters: [
    {
      name: "Will Smith",
      parents: [
        {
          name: "Vy Smith",
        },
      ],
    },
  ],
};

const willsMom = get(
  show,
  { path: "characters.parents.$.name", slots: [0] },
  "Aunt Viv"
);

console.log(willsMom); // "Vy Smith"
  • Uses lodash.get under the hood (fast, battle-tested, reliable)
  • Adds as much type safety as possible
  • Isomorphic (works both in the browser and in node)
  • 100% test coverage

@baublet/ts-object-helpers on NPM

Requirements

  • TypeScript 4.1+ (requires template literal types)

Documentation

Installation

# npm
$ npm i --save @baublet/ts-object-helpers

# yarn
$ yarn add @baublet/ts-object-helpers

Type Helpers

NestedPropertyTypeOf<T extends object, DotNotationKeyOf<T>>

Takes an object with a known set of keys and values, and some dot-notation property of that objects, and creates a type that represents the value of the accessed property.

type Model = {
  id: string;
  child: {
    id: string;
    children: {
      id: string;
      name: string;
    }[];
  };
};

type ChildNameType = NestedPropertyTypeOf<Model, "id.child.children.$.name">; // string

DotNotationKeys<T extends object>

Takes an object with a known set of keys and recursively returns all possible dot notation accessors for the known type.

type Model = {
  id: string;
  child: {
    id: string;
    children: {
      id: string;
      name: string;
    }[];
  };
};

type ModelKeys = DotNotationKeys<Model>;

// The above type is equivalent to the below:
type FlatModelKeys =
  | "id"
  | "child"
  | "child.id"
  | "child.children"
  | "child.children.$"
  | "child.children.$.id"
  | "child.children.$.name";

DotNotationMap<T extends object>

Flattens an object nested up to 5 levels deep into a record of the nested keys in dot notation, with the values preserved.

Note: this generic is best used on known types. For example, Record<string, KnownType> won't work well with this type, since we can't infer the infinite possible combination of keys on Record<string, KnownType>.

type Model = {
  id: string;
  child: {
    id: string;
    children: {
      id: string;
      name: string;
    }[];
  };
};

type DotNotatedModel = DotNotationMap<Model>;

// The above type is equivalent to the below:
type FlatModel = {
  id: string;
  child: { id: string; children: { id: string; name: string }[] };
  "child.id": string;
  "child.children": { id: string; name: string }[];
  "child.children.$": { id: string; name: string };
  "child.children.$.id": string;
  "child.children.$.name": string;
};

NonObjectKeysOf<T extends object>

Returns the keys of T that are primitive types (that is, they're not objects).

ObjectKeysOf<T extends object>

Returns the keys of T that are objects or object-like.

PrependObjectKeysWith<T extends object, Key extends string>

Creates a new object from T with the keys prepended with Key. If Key is an empty string, this returns T.

UnionToIntersection<T extends object>

If T is a union of objects, converts T to an intersection between all of the objects unioned in T. Credit: S Stefan Baumgartner

ValuesOf<T extends object>

Constructs a type from all of the values of T as a union.

type Model = {
  id: "id";
  object1: { test: 123 };
};

// Values = "id" | { test: 123 }
type Values = ValuesOf<Model>;

const values: Values[] = ["id", { test: 123 }];

Functions

get

Type-safe accessor function for objects with known keys and values. Similar API to lodash.get.

function get(
  subjectObject: object,
  optionsOrPath:
    | string
    | {
        path: string;
        slots?: (string | number)[];
      },
  defaultValue?: any
): ProvidedDefault | object[path];

Example

const person = {
  id: "a10023b",
  name: "Carlton Banks",
  dean: {
    id: "p93i",
    name: "Ashley Banks",
  },
  departments: [
    {
      id: 1,
      name: "History",
      chair: {
        id: "a43c",
        name: "Vivian Banks",
      },
    },
    {
      id: 2,
      name: "Literature",
      chair: {
        id: "a88p",
        name: "Hillary King Banks",
      },
    },
  ],
};

const deanName = get(
  person,
  "dean.name".
  "n/a"
); // type: string | "n/a". Value: Ashley Banks

const firstDepartmentName = get(
  person,
  { path: "department.$.name"), slots: [0] }
); // type: string. Value: History

const secondDepartmentName = get(
  person,
  { path: "department.$.name"), slots: [1] }
); // type: string. Value: Literature

const secondDepartmentChair = get(
  person,
  { path: "department.$.chair"), slots: [1] }
); // type: undefined | { id: string, name: string }. Value: { id: "a88p", name: "Hillary King Banks" }

Limitations

  • This only works on fully known object types (e.g., where properties of the object are all known at compile time)
  • If values aren't fully known at compile time, this may not work properly.
  • If the accessors aren't fully known at compile time, this may not work properly.

For more complex examples, type safety cannot guaranteed at compile time. Use lodash.get and runtime checks for these scenarios.