1

I have a react component, which is a form, and the input IDs need to be passed to its' props. It also accepts a submit handler, which should get an object with the same keys as the passed inputs' IDs.

Here's an example:

const inputs = [
  { id: 'first' },
  { id: 'second' },
];

//the parameter's keys should match the inputs' IDs
type ExpectedValues = {
  first: string;
  second: string;
};
const handleSubmit = (valuesById: ExpectedValues) => {};

const ExampleForm = () => (
  <Form
    inputs={inputs}
    onSubmit={handleSubmit}
    //Type '{ [inputId: string]: string; }' is missing the following properties         
    //from type 'ExpectedValues': first, second
  />
);

type Input = {
  id: string;
};
/*
  some magic would be needed here in the types to check the inputs IDs,
  and onSubmit should get those as keys in the object
*/
type Props = {
  inputs: Input[];
  onSubmit: (values: { [inputId: string]: string; })
}

const Form: FC<Props> = props => null;

1
  • 1
    I don't think this is possible. Maybe try with enums Commented May 15, 2020 at 21:24

1 Answer 1

1

You need readonly arrays to get correct types for keys. TS will infer just string otherwise.

Try something like this:

type Input = {
    readonly id: string;
};

type InputList = Readonly<Input[]>;

type Props<
        Inputs extends InputList = any,
        IFlat = Inputs[number],
        Ids = IFlat[Extract<keyof IFlat, 'id'>]
> = {
    inputs: Inputs;
    onSubmit: (values: {
        [P in Extract<Ids, string>]: string
    }) => void;
};

function Form<I extends InputList>(props: Props<I>) {
    return null;
}

function TestForm() {
    return (
        <Form
            inputs={[{ id: 'goodKey' }] as const}
            onSubmit={values => {
                console.log(values.goodKey);
                console.log(values.badKey);
            }} 
        />
    );
}

You should get an error on console.log(values.badKey);

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

1 Comment

Inside the body of form (state, handlers, etc.), it makes the code messy, but works like a charm. I asked this question with no hope, but it seems like TypeScript is more flexible than I thought.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.