I want to define an interface with generic type that have to accept an object having its keys as "root fields name" and the value as an array of objects that defines some sub-fields having the key as the name of the sub-field and the type as the type of the field value. Something like this:
interface Inputs{
emails: { email: string, active: boolean, i: number }[]
}
const obj:Inputs = {emails: [ {email: "...", active: true, i: 100} ]}
The interface who receive this as a generic type have a "name" property that will receive the (keyof) name of the sub-field ( ex. active ) and a function with a parameter that have to receive the type of the sub-field defined in the name property.
Something like this
[
{
name: "active",
component: ({ value, values }) => {
console.log(value, values);
return <>Component</>;
}
}
]
In this example, value must have "boolean" as only accepted type since the active key in the object has a boolean type.
I managed to get almost everything I wanted to do. The only problem is that instead of receiving the exact type of the subfield, the parameter of the function gets a union of all types of the object.
So in the previous example, since "email" is a string type, value should be string type, instead the receiving type is string | number | boolean ( all the available types in the object ).
I don't know if I have been able to explain myself well, but I have prepared a sandbox to do it better
https://codesandbox.io/s/boring-fast-pmmhxx?file=/src/App.tsx
interface Options<
T extends { [key: string]: unknown }[],
Key extends keyof T[number]
> {
values: T;
value: Key;
}
interface InputDef<
T extends { [key: string]: any }[],
Key extends keyof T[number]
> {
name: Key;
component: (props: Options<T, T[number][Key]>) => React.ReactNode;
}
interface Props<T extends { [key: string]: [] }, Key extends keyof T> {
name: Key;
inputs: InputDef<T[Key], keyof T[Key][number]>[];
callback: (values: T) => void;
}
interface Inputs {
firstName: string;
lastName: string;
emails: { email: string; active: boolean; other: number }[];
}
const GenComponent = <T extends { [key: string]: any }, Key extends keyof T>({
name,
inputs
}: Props<T, Key>) => {
console.log(inputs);
return (
<div>
{name} {JSON.stringify(inputs)}
</div>
);
};
interface MainComponentProps {
callback: TestCallback<Inputs>;
}
const MainComponent: React.FC<MainComponentProps> = ({ callback }) => {
return (
<>
<GenComponent
callback={callback}
name="emails"
inputs={[
{
name: "active",
component: ({ value, values }) => {
console.log(value, values);
return <>Component</>;
}
}
]}
/>
</>
);
};
type TestCallback<Data> = (values: Data) => void;
function test<Data>(values: Data): void {
console.log(values);
}
export default function App() {
return (
<div className="App">
<MainComponent callback={test} />
</div>
);
}
On line 57, since the name in the object is "active" the type of value should be "boolean" instead of "string | number | boolean". How can I achieve this?
Thanks!