I have some TypeScript code where I'm trying to extract data- attributes from a full object of element attributes. However, I'm running into an error, "Type instantiation is excessively deep and possibly infinite.(2589)".
I think my code can probably be optimized to fix this—I might be overcomplicating it—so I'd appreciate an expert eye to see if it can be helped, or if what I'm trying to do is too difficult.
Here's a link to the TS Repl, and I've included the code below:
type AnyArray = any[];
type AnyArrayWithItems = [any, ...any];
type AnyFunction<Arguments extends any[] = any[]> = (...args: Arguments) => any;
// The type of the first item in an array.
// Input: `[1, 2, 3]`
// Output: `1`
type Head<SomeArray extends AnyArray> = SomeArray extends AnyArrayWithItems
? SomeArray[0]
: never;
// The type of an array after removing the first element.
// Input: `[1, 2, 3]`
// Output: `[2, 3]`
type Tail<SomeArray extends AnyArray> = AnyFunction<SomeArray> extends (
_: any,
...args: infer Remainder
) => any
? Remainder
: never;
const DATA_KEY_PREFIX = "data-" as const;
type DataKey = `${typeof DATA_KEY_PREFIX}${string}`;
type PrependIfDataKey<
Key extends string | number | symbol,
> = Key extends DataKey ? [Key] : [];
type DataKeys<
Keys extends (string | number | symbol)[],
> = Keys['length'] extends 0 ? [] : [
...PrependIfDataKey<Head<Keys>>,
...DataKeys<Tail<Keys>>
];
type DataProps<Props extends Record<string, unknown>> = Pick<
Props,
DataKeys<(keyof Props)[]>
>;
function getDataAttributes<Props extends Record<string, unknown>>(
props: Props,
): DataProps<Props> {
return Object.keys(props)
.filter((propName): propName is DataKey =>
propName.startsWith(DATA_KEY_PREFIX),
)
.reduce(
(dataProps, propName) => ({ ...dataProps, [propName]: props[propName] }),
{} as DataProps<Props>,
);
}
const test = { href: "#", onClick: () => null, 'data-foo': 'bar' };
const attrs = getDataAttributes(test);