Skip to content

Spreading object with optional property causes incorrect type inference when exactOptionalPropertyTypes = falseΒ #62906

@ptandler

Description

@ptandler

πŸ”Ž Search Terms

spread optional property undefined

πŸ•— Version & Regression Information

5.9.3 and others

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.9.3#code/MYewdgzgLgBAhjAvDA3jAHgLhgFgEwwC+AsAFCiSwBGAjEqhtgK5gAmApgGYCWY7rRMhWgxgdZGgB00uABoY0ybSIwA9KphQAngAd2MEJ1F1uEGL07sATlf7wzaLDBYcefVgG4VAWk0ALOCgAcjNQG3ZgWEBQciFwCBAAG3ZJBJAAcwAKMQBKMljKGCo8bEcAfmwwJgBbKmsVCUZnNi5eO0I1DSg-UxhWEHYzMBBYHSsQViZgfTgwGGsxqxgAdz92WfZ0OEiAeR0obnA4BIAFMb0rbQAVXQHETiOIdnyRYAIGxTkFaSKVdU0bgxGV7mMwWeZ2OAORqVGrWLztXxdQIhZZjMBpeSQ0R4SToGAAfVM+KarlaAkAMuTPRLJVKZV65UhAA

πŸ’» Code

const a = { x: 42 }
const b1 = { x: undefined }
const c1 = { ...a, ...b1 } // type of c1 is inferred as { x: undefined; } - that's correct βœ…
console.log(c1)

const b2: { x?: number } = { x: undefined } // this does not produce an error when exactOptionalPropertyTypes=false
const c2 = { ...a, ...b2 } // type of c2 is inferred as { x: number; } - that's wrong, as c2.x _is_ undefined ❌
console.log(c2)

πŸ™ Actual behavior

I know that there have been several issues filed before like #57086 / #51755 / #51253 / #57408 and they all were closed referring to exactOptionalPropertyTypes.

However, reading the docs, the description of exactOptionalPropertyTypes says:

exactOptionalPropertyTypes makes TypeScript truly enforce the definition provided as an optional property:

const settings = getUserSettings();
settings.colorThemeOverride = "dark";
settings.colorThemeOverride = "light";

// But not:
settings.colorThemeOverride = undefined;

Type 'undefined' is not assignable to type '"dark" | "light"' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the type of the target.

So, the option changes the way, how ?: is defined from "can be not present or undefined" to "can be not present, but not set to undefined".

But even when exactOptionalPropertyTypes=false, I don't see a reason why TS should infer an invalid type in the example given above. It knows that x can be undefined (or not present) and it knows that exactOptionalPropertyTypes=false, so it should really infer in this case that the prop value can be undefined. For me, that would appear to be a consistent implementation of the language semantics.

Or do I miss something?

πŸ™‚ Expected behavior

I want to rely on TS inferring correct types, also in this case.

Additional information about the issue

Of course, this change would be a breaking change, so there could be another option to activate it.

We have a large project and there are many places (including JSON stored in customer DBs) that would need to be adjusted if we want to set exactOptionalPropertyTypes to true. So that's not a solution we can quickly implement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions