join

Object join technics.

This project is maintained by lopatnov

@lopatnov/join

A TypeScript library providing SQL-like join operations for JavaScript objects. Merge two objects using one of 9 composable join types, with support for deep merging of nested objects.

npm downloads npm version License GitHub issues GitHub stars


Table of Contents


Installation

npm install @lopatnov/join

Browser:

<script src="https://lopatnov.github.io/join/dist/join.umd.min.js"></script>

Import

TypeScript / ES Modules

import { join, JoinTypes } from "@lopatnov/join";

CommonJS

const { join, JoinTypes } = require("@lopatnov/join");

Join Types

Join Types

The library uses a 4-bit flag system to describe which parts of two objects appear in the result:

Bit Name Meaning
3 left Include properties unique to the left object
2 innerLeft Include shared properties, keeping left values
1 innerRight Include shared properties, using right values
0 right Include properties unique to the right object

Named Join Types

Join Type Bits Description
none 0000 Empty result — no properties from either object
left 1000 Only properties unique to the left object
right 0001 Only properties unique to the right object
innerLeft 0100 Shared properties only, keeping left values
innerRight 0010 Shared properties only, replacing with right values
innerJoin 0110 Shared properties, deep-merged (left + right values combined)
leftJoin 1110 Left-unique + shared properties (deep-merged)
rightJoin 0111 Shared properties (deep-merged) + right-unique
fullJoin 1111 All properties from both objects, shared ones deep-merged
expand 1011 Left-unique + right values for shared + right-unique (default)

Custom join types can be composed with bitwise OR:

const customJoin = join(JoinTypes.left | JoinTypes.innerLeft | JoinTypes.right);

API

function join(
  joinType?: JoinTypes
): <TContext>(
  context: TContext
) => <TJoinObject>(joinObject: TJoinObject) => TContext & TJoinObject;

join uses a curried three-step pattern:

Step Call Description
1 join(JoinTypes.xxx) Set the join type; returns a context-setter function
2 contextSetter(leftObject) Set the left object; returns a joiner function
3 joiner(rightObject) Set the right object; returns the merged result

JoinTypes.expand is the default join type when join() is called with no arguments.


Usage Examples

Right Join

Returns only the properties unique to the right object:

const rightJoin = join(JoinTypes.right);

const contextJoinBy = rightJoin({
  sample1: "One",
  sample2: "Two",
  sample3: "Three"
});

const result = contextJoinBy({
  sample2: "Dos",
  sample3: "Tres",
  sample4: "Quatro"
});

console.log(result); // { sample4: "Quatro" }

Left Join

Returns only the properties unique to the left object:

const leftJoin = join(JoinTypes.left);

const contextJoinBy = leftJoin({
  sample1: "One",
  sample2: "Two",
  sample3: "Three"
});

const result = contextJoinBy({
  sample2: "Dos",
  sample3: "Tres",
  sample4: "Quatro"
});

console.log(result); // { sample1: "One" }

Custom Bitwise Composition

Returns left-unique + shared (from left) + right-unique properties:

const customJoin = join(JoinTypes.left | JoinTypes.innerLeft | JoinTypes.right);

const contextJoinBy = customJoin({
  sample1: "One",
  sample2: "Two",
  sample3: "Three"
});

const result = contextJoinBy({
  sample2: "Dos",
  sample3: "Tres",
  sample4: "Quatro"
});

console.log(result); // { sample1: "One", sample2: "Two", sample3: "Three", sample4: "Quatro" }

Inner Join (Deep Merge)

Returns shared properties with their values deep-merged:

const result = join(JoinTypes.innerJoin)({
  sample1: "One",
  sample2: "Two",
  sample3: { smile: "cheese" }
})({
  sample2: "Dos",
  sample3: { sorrir: "queijo" },
  sample4: "Quatro"
});

console.log(result);
// { sample2: "Dos", sample3: { smile: "cheese", sorrir: "queijo" } }

Demo


Contributing

Contributions are welcome! Please read CONTRIBUTING.md before opening a pull request.


Built With


License

Apache-2.0 © 2020–2026 Oleksandr Lopatnov · LinkedIn