undefined
undefined

Reputation: 6854

Typescript infer the returned array type elements

I have the following function:

const data = {
  id: 1,
  name: '',
}

type keysType = keyof(typeof data);

function getKeysValues(...keys: keysType[]) {
  return keys.map(k => data[k]);
}

const value = getKeysValues('id', 'name');

The type of value is (string | number)[]. How can I change it to be dynamic based on the passed keys? So, in the above case I'm expecting the type to be [number, string].

Upvotes: 3

Views: 7212

Answers (2)

Tomasz Gawel
Tomasz Gawel

Reputation: 8520

The simplest way to go:

function getKeysValues(...keys: Array<keyof typeof data>): Array<typeof data[keyof typeof data]> {
    return keys.map(k => data[k]);
}

You may also add generics:

function getKeysValues<K extends keyof typeof data>(...keys: Array<K>): Array<typeof data[K]> {
    return keys.map(k => data[k]);
}

But for convenience in any of the above cases I would type-aliased the typeof data

type Data = typeof data;
// then
function getKeysValues(...keys: Array<keyof Data>): Array<Data[keyof Data]>;
// or
function getKeysValues<K extends keyof Data>(...keys: Array<K>): Array<Data[K]>;

Upvotes: 1

Nail Achmedzhanov
Nail Achmedzhanov

Reputation: 1494

Use mapped types on tuples TypeScript 3.1

const data = {
  id: 1,
  name: '',
}

type Data = typeof data;
type DataKeysType = keyof(typeof data);
type DataFieldType<T> = T extends DataKeysType ?  Data[T] : never;

type MappedDataTuple<T extends DataKeysType[]> = {
    [K in keyof T]: DataFieldType<T[K]>;
}

function getKeysValues<T extends DataKeysType[]>(...keys: T): MappedDataTuple<T> {
  return <any>keys.map(k => data[k]);
}

// const value: [number, string]
const value = getKeysValues('id', 'name');

Upvotes: 4

Related Questions