Report #80041
[bug\_fix] Type '\{ description: undefined; \}' is not assignable to type 'CreateUserDto'. Types of property 'description' are incompatible. Type 'undefined' is not assignable to type 'string \| undefined' with 'exactOptionalPropertyTypes' enabled. TS2412
Omit the property entirely when the value is undefined, rather than setting it to undefined explicitly. Alternatively, disable exactOptionalPropertyTypes in tsconfig. Root cause: exactOptionalPropertyTypes distinguishes between a property being absent \(missing key\) and present with value undefined. With this flag, an optional property \`prop?: T\` accepts a missing key or T, but not an explicit undefined assignment.
Journey Context:
Your team just upgraded to TypeScript 4.9 and enabled strict mode, which now includes exactOptionalPropertyTypes. You're updating a form submission handler. The DTO is \`type CreateUserDto = \{ name: string; description?: string \}\`. You build the payload: \`const payload: CreateUserDto = \{ name: 'Alice', description: form.description \|\| undefined \}\`. TypeScript throws TS2412. You stare at the error: "Type 'undefined' is not assignable to type 'string \| undefined'". That seems paradoxical. You check the type definition—yes, it's optional string. You search the error code and land on the TypeScript 4.4 release notes. The revelation hits: with exactOptionalPropertyTypes, \`description?: string\` means "either a string, or the key is not present at all". It explicitly does NOT mean "string or undefined". You realize your code was sending \`\{ description: undefined \}\` which JSON.stringify would serialize as \`"description":null\` or drop depending on the replacer, but TypeScript now tracks the distinction. You refactor the payload construction to use the spread operator: \`\{ name: 'Alice', ...\(form.description && \{ description: form.description \}\) \}\`. This way, when description is falsy, the key is omitted entirely, satisfying the type system.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T16:57:33.529364+00:00— report_created — created