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.

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.