title: Yup, Typescript and React multi-step form: how to type parent state
body: <h1>The context</h1>
  <p>I've got a multi-step form which consists of 4 steps. Each step, of course, has different fields and different validations have to be made.</p>
  <p>All of the form data, however, is stored in the parent component, which is the step orchestrator, and this sends the information down to each step. Once the &quot;continue&quot; button is pressed in each step, <strong>the information is stored in the parent state</strong> to be able to navigate between steps without losing information.</p>
  <h1>The (very schematic) example</h1>
  <pre><code>const FormParent: React.FC = () =&gt; {
    const [formData, setFormData] = useState&lt;?&gt;({stepA: {}, stepB: {}});
    const [step, setStep] = useState&lt;number&gt;(0);
    
    return (step === 0 
      &amp;&amp; &lt;StepA formData={formData} onSubmit={setFormData} /&gt; 
      || &lt;StepB formData={formData} onSubmit={setFormData} /&gt;
    );
  };
  
  const StepA: React.FC&lt;StepProps&gt; = ({formData, onSubmit}) =&gt; {
    const fieldsSchema = object({
      propA: string().required(),
      propB: object(),
      propC: number(),
    });
  
    const [fieldsState, setFieldsState] = useState&lt;InferType&lt;typeof fieldsSchema&gt;&gt;(formData.stepA);
  
    const handleSubmit = () =&gt; {
      if (fieldSchemaIsValid(fieldsSchema, fieldsState)) { // perform custom validation
        onSubmit((current) =&gt; ({ ...current, stepA: {...fieldsState} }));
      }
    };
  
    return (...);
  };
  </code></pre>
  <h1>The problem</h1>
  <p>Everything works great, except for the <strong>typings of the state object and its steps</strong>.</p>
  <h2>Problem A</h2>
  <p>As Yup has its own schema and type infering methods, I cannot use any interface to specify the fields' type. For example, <strong>I cannot do this</strong>:</p>
  <pre><code>  const fieldsSchema = object({
      propA: string().required(),
      propB: object&lt;MyCustomType&gt;(),
      propC: number(),
    });
  
    const [fieldsState, setFieldsState] = useState&lt;InferType&lt;typeof fieldsSchema&gt;&gt;();
  </code></pre>
  <p>This creates the first conflict: the state is first initialized in the <code>FormParent</code> (with a type <code>T</code>) and I don't have the <code>fieldsSchema</code> for each step in that parent component, as I'd like to <strong>keep them specific to each form step</strong>. This results in types from the parent state and the step fields' state not matching.</p>
  <h2>Problem B</h2>
  <p>The second conflict comes to type validation. If I set the state to a specific type, such as:</p>
  <pre><code>const [formData, setFormData] = useState&lt;MyFormDataType&gt;({ step1: {}, step2: {} }); 
  </code></pre>
  <p>Either I make each <code>stepX</code> prop optional, or I use <code>&lt;Partial&lt;MyFormDataType&gt;&gt;</code>. Otherwise, I cannot set <strong>the initial step to empty</strong>, but I need to do that because I don't have any of the user's input information yet.</p>
  <p>At the end, I end up setting up a type for the <code>formData</code> which is not correct (as <code>Partial</code> will make everything nullable and it should not be when we've got that information), and then <strong>in each step I have to repeat that same object structure with <code>Yup</code> format</strong>, like:</p>
  <pre><code>interface Account {
    id: string;
    clientId: string;
    label: string;
    amount: number;
  }
  
  const fieldsSchema = object({
    propA: string().required(),
    propB: object().shape({
      id: string(),
      clientId: string(),
      label: string(),
      amount: number(),
    }),
    propC: number(),
  });
  </code></pre>
  <p>If I change the props in the <code>Account</code> interface, I'd have to change all of the <code>shape</code>'s in all of the steps that use that interface, which is not nice.</p>
  <h2>Problem B.2</h2>
  <p>Even if I went with this and made two different Interfaces: one for the <code>formData</code> (as it needs to be <code>Partial</code> because we don't have all the information), and one to cast it at the end of the form to meet any possible API requirements (with all the final required fields and so on, without <code>Partial</code>, to make sure everything is in place), whenever I try to cast it I get errors telling me that <code>Type string|undefined is not assignable to type string</code>, so I'd have to iterate every prop of the object and cast it.</p>
  <h1>The questions</h1>
  <p><strong>Question A:</strong> Can Types be used in <code>yup</code> fields schema so the final casting is made easier or, at least, I don't have to repeat the <code>shape</code> structure in every step where that type is used?</p>
  <p><strong>Question B:</strong> Is there any way to specify a Type for the parent <code>formData</code> being able to leave it empty as we don't have the user's input yet? (I guess the use of <code>Partial</code> for that is mandatory, which leads to next question).</p>
  <p><strong>Question C:</strong> How can I cast a <code>Partial</code> type to the same type without <code>Partial</code>, without having to iterate for each prop to cast it? I've seen if I use <code>as unknown as MyCustomFinalType</code> to cast it it does not complain, but I don't know if that's the best way to do it.</p>
  <p>Thank you!</p>