Maciej Radzikowski
Maciej Radzikowski

Reputation: 2477

Infer type of array items under object key

I have a Datum<T> type where T may be either a number or a string. Datums are collected as arrays in an object. I have an aggregateDatums function that takes object, key name with Datums array, and returns a datum as well.

export interface Datum<T extends string | number> {
    key: T;
    count: number;
}

const aggregateDatums = <
    TKey extends string | number,
    T extends { [k in K]: Datum<TKey>[] },
    K extends keyof T
    >(data: T, key: K): Datum<TKey>[] => {
    return [];
};

const data = {
    numeric: [{key: 1, count: 1}, {key: 2, count: 2}],
    text: [{key: 'a', count: 1}, {key: 'b', count: 2}],
};

const aggregated = {
    numeric: aggregateDatums(data, 'numeric'), // should be type Datum<number>[], but is Datum<string | number>[]
    text: aggregateDatums(data, 'text'), // should be type Datum<string>[], but is Datum<string | number>[]
};

TypeScript playground

Because I pass an object and a key that holds array, not an array of Datums directly, the result is typed Datum<string | number>[]. My goal is the type to correspond to the type of Datums in source array, so Datum<string>[] or Datum<number>[]. Any tips on how can I achieve this?


The example is simplified to show the problem only. But if I overengineered typings that can be done simpler, please let me know.

Also, I would be grateful if someone can recommend resources on advanced typings in TypeScript. Unfortunately, most resources is about types like Partial<T> etc, while I know you can do advanced magic with types :-)

Upvotes: 0

Views: 82

Answers (1)

HTN
HTN

Reputation: 3594

const aggregateDatums = <
    T extends { [k in K]: Datum<string | number>[] },
    K extends keyof T
    >(data: T, key: K): T[K] extends Datum<infer P>[] ? Datum<P>[] : never => {
    throw 'implemented';
};

Upvotes: 1

Related Questions