3

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 2

3

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

Sign up to request clarification or add additional context in comments.

2 Comments

Hey thank you so much! That works perfectly. I have a problem though: From the outside the type checking works exactly as intended, but when I create an API object (const api: Api = { state, water, version };) TS tells me that Property 'type' is missing in state, water and version. Currently those variables are of the type Converter, if I change the type to IExtendedConverter it tells me Property 'type' is missing in type but I don't know how to define it
Hey, I added type?: T; to Converter and got rid of IExtendedConverter and kept the rest as you suggested. This works perfectly for me. Thank you!
0

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.

1 Comment

hey thanks! that is what I am doing now! but I had to make the converter property optional or I would have to actually set that field with every usage of the interface. Thank you very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.