TypeScript: Unexpected Behavior with Mapped Types and Conditional Types for Form Validation
I recently switched to I've looked through the documentation and I'm still confused about I've searched everywhere and can't find a clear answer... I'm working on a form validation utility in TypeScript where I want to create a mapped type that checks if all fields in a given interface are valid. The validation function should return a type that reflects the validity of each field based on whether it's required or optional. However, I am encountering an issue where TypeScript does not seem to infer the types correctly when I use both mapped and conditional types. Here's what I've tried: Given the following interface for a user form: ```typescript interface UserForm { username: string; email?: string; age?: number; } ``` And the following mapped type I created to validate the required fields: ```typescript type ValidationResult<T> = { [K in keyof T]: T[K] extends undefined ? 'Required' : 'Valid'; }; ``` I expected that when I pass `UserForm` to `ValidationResult`, the result should reflect the optional fields correctly. However, when I use it like this: ```typescript type UserValidation = ValidationResult<UserForm>; ``` The inferred type for `UserValidation` is coming out as: ```typescript { username: 'Valid'; email: 'Valid'; age: 'Valid'; } ``` This is incorrect because it doesn't check if `email` and `age` could be required based on other conditions in my application. I also tried modifying the mapped type with a conditional check for `undefined`, but it still doesn't give the expected results. Hereβs the modified version: ```typescript type ValidationResult<T> = { [K in keyof T]-?: T[K] extends undefined ? 'Required' : 'Valid'; }; ``` This still results in the same output. I am unsure how to adjust the type inference so that it checks for optional fields correctly. Any insights on how I can resolve this and get the expected validation results would be greatly appreciated! I am using TypeScript 4.5.2. What am I doing wrong? Any ideas how to fix this? For reference, this is a production mobile app.