Skip to content

Incorrect type inference for a field that is not optional, but has type of a union with undefined #524

@vladislavsheludchenkov

Description

@vladislavsheludchenkov

Bug Report

Actual behavior

If there is a non-optional attribute in an object that has a type of something | undefined, the logic that is skipping undefined is not reflected in the type, but still works in runtime:

import { deepmerge } from 'deepmerge-ts'

const a: { foo: string } = { foo: 'bar' }
const b: { foo: number | undefined } = { foo: undefined }

const c: { foo: number | undefined } = deepmerge(a, b)

console.dir(c) // { foo: 'bar' }

That results in a compile-time type diverging from a runtime type (in the example, it's string in runtime and number | undefined in compile-time)

The issue is not there if the field is marked as optional:

const a: { foo: string } = { foo: 'bar' }
const b: { foo?: number | undefined } = { foo: undefined }

const c: { foo: string | number } = deepmerge(a, b)

Expected behavior

The logic that filters out undefined should be reflected in the type even if an optional field is represented via union, and not using a ?:

const a: { foo: string } = { foo: 'bar' }
const b: { foo: number | undefined } = { foo: undefined }

const c: { foo: string | number } = deepmerge(a, b)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Status: ReleasedIt's now live.Type: BugInconsistencies or issues which will cause a problem for users or implementors.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions