TypeScript: Read generic type of value in object

Viewed 1607

I have this interface:

interface Api {
  state: Converter<State>;
  water: Converter<Water>;
  version: Converter<Versions>;
}

and I have a function called write

write(name, value);

now what I want to achieve is that the type of value should be the generic of Converter depending on the first parameter (name).

So if I call write("state", value) -> value should be State. The same goes for "water" and "version".

write("state, value);    // value should be type of State
write("water", value);   // value should be type of Water
write("version", value); // value should be type of Versions

I implemented the first parameter like so:

write(name: keyof Api, value: ???)

I found that I can get the corresponding value to keyof Api like so:

write<K extends keyof Api>(name: K, value: Api[K])

but that gives me Converter<State> for "state". Is there a way I can access the generic in Converter?

2 Answers

if you have acces to Converter iterface/type or whatever just extend it with this type

or create extended interface like this

interface Converter<T> {
  p1: any;
  p2: any;
}
interface IExtendedConverter<T> extends Converter<T> {
  type: T;
}

interface IApi {
  state: IExtendedConverter<string>;
  water: IExtendedConverter<number>;
}

const write = <K extends keyof IApi>(name: K, value: IApi[K]['type']) => {
  return;
};

const str = write('state', '1'); // here value has to be string
const num = write('water', 1); // here value has to be number

EDIT based on question

one solution would be define this parameter

const extendedConverterState: IExtendedConverter<string> = {
  ...converter,
  type: '',
};

const extendedConverterNumber: IExtendedConverter<number> = {
  ...converter,
  type: 1,
};

const api: IApi = {
  state: extendedConverterState,
  water: extendedConverterNumber,
};

this is somehow retarded solution since you would just create this property whitch will never be used.

other solution can be to create type parameter as optionla

interface IExtendedConverter<T> extends Converter<T> {
  type?: T;
}

but this souliton will ceate your parameter in write function as optional (possible undefined)

well maybe ther is better solution to acces this generic type. idk

I don't know if this helps, since I'm not sure what your Converter interface looks like.

But with this:

interface Converter<T> {
  converter: T;
}

And these interfaces for State, Water and Version:

interface State {
  state: string;
}

interface Water {
  water: string;
}

interface Version {
  version: string;
}

You can do this:

function write<K extends keyof Api>(name: K, value: Api[K]["converter"]) {}
write("state", { state: "x" }); // Works

write("water", { state: "x" }); // Argument of type '{ state: string; }' is not assignable to parameter of type 'Water'.

write("water", { water: "x" }); // Works

But it adds a property to your Converter interface.

Related