Skip to content

Instantly share code, notes, and snippets.

@waynevanson
Created June 17, 2020 10:19
Show Gist options
  • Save waynevanson/64422549f92d3b6e90d2d1dccbacd05f to your computer and use it in GitHub Desktop.
Save waynevanson/64422549f92d3b6e90d2d1dccbacd05f to your computer and use it in GitHub Desktop.
/*
FREE TO USE! COPY AND PASTE INTO YOUR PROJECT. TELL YOUR FRIENDS ABOUT MAPPABLE TYPES!
How to use:
install dependencies (tree shakable):
`yarn add fp-ts ts-toolbelt normalizr`
Your schema definitions should look like this:
```ts
export type Axis = { id: string; cells: Cell[] };
export type Row = Axis;
export type Column = Axis;
export type Cell = { id: string; text: string };
export const cells = new normalizr_schema.Entity<Cell>("cells");
export const columns = new normalizr_schema.Entity<Column>("columns", {
cells: [cells],
});
export const rows = new normalizr_schema.Entity<Row>("rows", {
cells: [cells],
});
export const schema = {
cells: [cells],
columns: [columns],
rows: [rows],
};
```
*/
import { record } from "fp-ts";
import { pipe } from "fp-ts/lib/function";
import {
denormalize as _denormalize,
normalize as _normalize,
schema,
} from "normalizr";
import { A } from "ts-toolbelt";
export type InputSchema = Record<string, schema.Entity[]>;
export type NormalizeData<R extends InputSchema> = A.Compute<
EntitiesSchemaToDataType<R>
>;
export type NormalizeResult<R extends InputSchema> = A.Compute<
EntitiesFlatten<R>
>;
export function normalize<
R extends InputSchema,
D extends NormalizeData<R>,
N extends NormalizeResult<R>
>(schema: R, data: D): N {
return _normalize(data, schema).entities as N;
}
export function denormalize<R extends InputSchema>(schema: R) {
return (
state: A.Compute<EntitiesFlatten<R>>,
recordIds: Partial<{ [P in keyof R]: string[] }>
) => {
const empty = pipe(
schema,
record.map(() => [] as string[]),
(a) => ({ ...a, ...recordIds })
);
return _denormalize(empty, schema, state) as A.Compute<
EntitiesSchemaToDataType<R>
>;
};
}
export type FlattenUnion<T extends object> = {
[P in keyof T]: T[P] extends Array<infer U>
? U extends object
? Array<string | U>
: never
: T[P] extends object
? string | T[P]
: T[P];
};
export type Flatten<T extends object> = {
[P in keyof T]: T[P] extends Array<infer U>
? U extends object
? Array<string>
: never
: T[P] extends object
? string
: T[P];
};
export type EntitiesSchemaToDataType<S extends InputSchema> = {
[P in keyof S]: S[P] extends schema.Entity<infer T>[]
? T extends object
? FlattenUnion<T>[]
: never
: never;
};
export type EntitiesFlatten<S extends InputSchema> = {
[P in keyof S]: S[P] extends schema.Entity<infer T>[]
? T extends object
? Record<string, Flatten<T>>
: never
: never;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment