Skip to content

Instantly share code, notes, and snippets.

@bradparker
Last active December 15, 2023 02:54
Show Gist options
  • Save bradparker/454c6bcfdd726a4ce6f49feb6eea852c to your computer and use it in GitHub Desktop.
Save bradparker/454c6bcfdd726a4ce6f49feb6eea852c to your computer and use it in GitHub Desktop.
Chunk array of discriminated union by discriminant?
const isDiscriminant = <TypeName extends string, T extends { type: TypeName }>(
type: TypeName,
candidate: { type: string }
): candidate is T => type === candidate.type;
type Chunk<
TypeName extends string,
T extends { type: TypeName } = any & { type: TypeName }
> = {
type: TypeName;
items: T[];
};
const discriminatedChunks = <
ATypeName extends string,
BTypeName extends string,
A extends { type: ATypeName } = any & { type: ATypeName },
B extends { type: BTypeName } = any & { type: BTypeName }
>(
types: [ATypeName, BTypeName],
items: (A | B)[]
): (Chunk<ATypeName, A> | Chunk<BTypeName, B>)[] =>
items.reduce<(Chunk<ATypeName, A> | Chunk<BTypeName, B>)[]>((acc, item) => {
const lastChunk = acc[acc.length - 1];
if (isDiscriminant(types[0], item)) {
if (lastChunk && isDiscriminant(types[0], lastChunk)) {
return acc
.slice(0, -1)
.concat({ type: types[0], items: lastChunk.items.concat(item) });
}
return [...acc, { type: types[0], items: [item] }];
}
if (lastChunk && isDiscriminant(types[1], lastChunk)) {
return acc
.slice(0, -1)
.concat({ type: types[1], items: lastChunk.items.concat(item) });
}
return [...acc, { type: types[1], items: [item] }];
}, []);
console.log(
discriminatedChunks<"a", "b">(
["a", "b"],
[
{ type: "a", foo: 1 },
{ type: "b", baz: 2 },
{ type: "b", baz: 3 },
{ type: "a", foo: 4 },
{ type: "a", foo: 5 },
{ type: "a", foo: 6 },
{ type: "b", baz: 7 },
]
)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment