Stefan
Stefan

Reputation: 11

Can I derive a return type directly depending on a function parameter in TS?

I'm reading from a data source where I know the return type for each lookup key. I defined this in the type DataLayout. I want to make the function getItem() generic and get the correct return type accordingly.

type DataLayout = {
  a: string
  b: number
}

const getItem = <T extends Record<string, unknown>>(key: string & keyof T) => {
  return getExternalItem(key) as T[typeof key]
}

const result = getItem<DataLayout>('a')

but result is of type string | number.

How do I make it string only? Is this possible?

Upvotes: 1

Views: 74

Answers (2)

vitoke
vitoke

Reputation: 748

In addition to captain-yossarian's anwer, I like to use a class for this. Also, I added an extra check to the getItem function to make sure that getItem('c') will give a compiler error.

type DataLayout = {
  a: string;
  b: number;
};

class Entity<T extends Record<string, unknown>> {
  getItem<K extends keyof T>(key: K & keyof T): T[K] {
    return null as any;
  }
}

const ent = new Entity<DataLayout>();

// type of result is string
const result = ent.getItem('a');

// this will give a compiler error:
ent.getItem('c');

Upvotes: 1

This can be done in a bit different way:

type DataLayout = {
  a: string
  b: number
}

declare var data: DataLayout;

const dataLayout = <Obj,>(obj: Obj) => <Prop extends keyof Obj>(prop: Prop) => obj[prop]

const withData = dataLayout(data)

const getItem = withData('a') // string
const getItem2 = withData('b') // number

Playground

In 79.8% cases, you should not use explicit generic, TS should infer it from some value

Upvotes: 1

Related Questions