Giter Site home page Giter Site logo

pojo-maps's Introduction

POJO Maps

In using React and Redux, you may find that you have to use POJO objects instead of ES6+ native objects like Set and Map. This project aims to provide a well typed, immutable POJO Map implementation that can simplify tasks you often do with POJO Maps.

See also pojo-sets

CICD Badge

Quick start

Install the package

yarn add pojo-maps

Import and start using it!

import { PojoMap } from 'pojo-maps';

const myMap = PojoMap.fromEntries(['a', 1]. ['b', 2]);

Usage

PojoMap are meant to be a drop-in replacement everywhere you use immutable Partial<Record<T, U>> structures. Their main benefit is to handle the ambiguity in Typescript around missing & "undefined" keys.

// Traditional Record types:
declare const items: Partial<Record<string, string>>;

// Lame
Object.values(items); // type: Array<string | undefined>
// Extra lame!!
items['myvalue'] = undefined;

// PojoMap:
declare const map: PojoMap<string, string>;

// Cool!
PojoMap.values(map); // type: Array<string>
// Wow! Error!!!
PojoMap.set(map, 'myvalue', undefined); // Argument of type 'undefined' is not assignable to parameter

The traditional record types require a manual type assertion. By using immutable helper methods, PojoMap can do all of the normal record operations in a typesafe manner.

Advanced Usage

PojoMap contains helper methods to do most common Object or Record operations.

const alphaNum = PojoMap.fromEntries([['a', 1], ['b', 2], ['c', 3]] as const);

const abcd = PojoMap.set(alphaNum, 'd', 4);
const abd = PojoMap.remove(abcd, 'c');

PojoMap.keys(abd); // ['a', 'b', 'd']
PojoMap.values(abcd); // [1, 2, 3, 4]
PojoMap.entries(alphaNum); // [['a', 1], ['b', 2], ['c', 3]]


// Pick or Omit Keys
const ab = PojoMap.pick(abcd, ['a', 'b']);
const cd = PojoMap.omit(abcd, ['a', 'b']);

// Add additional types to your map?
const empty = PojoMap.empty<string, string>();
const withNums = PojoMap.set(empty, 'a', 10);

// Convert a PojoMap into a PojoSet
const set = PojoSet.from(PojoMap.keys(alphaNum));

// Create a PojoMap through common high level reducer operations:
const pets = [{ name: 'Tacquito', kind: 'dog' }, { name: 'Olaf', kind: 'dog' }, { name: 'Clover', kind: 'cat' }];
const petsByName = PojoMap.fromIndexing(pets, pet => pet.name);
const petsByType = PojoMap.fromGrouping(pets, pet => pet.kind);
const petTypeCounts = PojoMap.fromCounting(pets, pet => pet.kind);

// Map a PojoMap's values
const petTypesByName = PojoMap.map(petsByName, pet => pet.kind);

TS Playground Demo

Project Goals

This project is almost trivial in terms of its JavaScript functionality. The true mission of this project is to improve handling around Record objects in TypeScript. In particular, these two scenarios:

  1. TypeScript#13195: TypeScript does not distinguish missing/undefined properties.
    • We want to provide consistent, practical types for get() and values() operations.
    • Standard Record or Partial<Record> in TS inconsistently give T | undefined vs T between rec[key] and Object.values(rec);
    • Our utility methods for PojoMap provide constraints & type assertions to give more useful types here.
    • Update: Introduced in TS 4.4, --exactOptionalPropertyTypes helps alleviate this issue.
  2. TypeScript#26797: Tag Types are not allowed as index signature parameter types.
    • DIY Tag Types, aka nominal types or opaque types, are not supported first party in TypeScript.
    • Unlike opaque types in flow, our DIY tag types cannot be used as index parameters.
    • Our utility methods for PojoMap provide type assertions to allow "indexing" a PojoMap using a tag type.

pojo-maps's People

Contributors

dependabot[bot] avatar icy-inferno avatar prodigysim avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

icy-inferno

pojo-maps's Issues

Add bulk remove

Would be somewhat nice to be able to bulk remove a number of keys, without the user having to manually call remove or other operations.

Add PojoMap.size

Add a method to get the number of items in the map (number of keys).

Consider differences from ES6 Map spec

ES6 Map has a few differences:

Removal method is "delete" instead of "remove"

I don't think this is a huge deal but we could add an alias if needed.

Has a "forEach" method

Is this better than object.entries()? Perhaps, since it doesn't copy.

function forEach(map, cb) {
  for(const key in map) {
    cb(map[key], key, map);
  }
}

Is it a good idea to let people run arbitrary code mid-iteration? Would we have to copy anyway?

forEach, keys, values, entries: Return values in insertion order.

All of these Map functions are specified to return values in insertion order.

It looks like our functions will do this, but it's not guaranteed in our spec yet. Can we and should we guarantee it in our spec & add unit tests?

> Object.keys({ ...{ a: 1, b: 2, c: 3}, d: 4})
Array(4) [ "a", "b", "c", "d" ]

Provide a quick cast factory for users

We should create a PojoMap.of() or a PojoMap.from() for casting map-like objects to PojoMaps quickly and safely. Many types can already be implicitly cast to PojoMap, so we should give people a way to do that cast without manually type asserting (with all of the generics...)

function of<K extends PropertyKey, V extends {}>(maplike: PojoMap<K, V>): PojoMap<K,V> {
    return maplike;
}

Examples

Proposal: Common operations interop

Common object/array-reduce operations may be difficult to convert into a PojoMap without manual casting.

If we can offer:

  • indexBy
  • groupBy
  • mapObject
  • countBy

In some form, with reasonable names, we can avoid manual casting from Record types.

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.