Skip to content

Discriminated union parameter destructuring doesn't work if the fields have defaults #50139

Open
@KrischnaGabriel

Description

@KrischnaGabriel

Suggestion

Cleverly preserve the conditional type of variables of an de-structured object, which may be of 2 or more object types.

🔍 Search Terms

in:title destructuring assignment condition*
in:title destructuring assignment object
in:title destructuring assignment or

✅ Viability Checklist

My suggestion meets these guidelines:

  • [true] This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • [true] This wouldn't change the runtime behavior of existing JavaScript code
  • [?] This could be implemented without emitting different JS based on the types of the expressions
  • [true] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • [true] This feature would agree with the rest of TypeScript's Design Goals.

💻 Use Cases

A component or function can work with two or more types. As an example let us say numbers and strings.
For the type string the component may accept additional properties, which are not applicable to numbers and vise versa.
This can be enforced by a type rule by creating multiple object types and allowing the input to only be one or the other

type inputObject = (
    {
        inputType: "number",
        multiply_by?: number
    } | {
        inputType: "string",
        makeUppercase?: boolean
    }
)
const func = (props:inputObject)=>{}

Now, it would be great if it would still be possible to use an destructuring assignment on the input object, wouldn't it?

📃 Motivating Example

The input to the function is an object. The general layout of the object stays the same, but the type rules should enforce a more specific rule, which allows properties to be of a certain type only if other properties are also of a certain specific type.

export default function Eingabefeld({
    isText=true,
    children="",
}:(
    {
        isText: true,
        children:string
    } | {
        isText: false,
        children:number
    }
)) { 
    if (isText === true) {
        let data:string = children
    }else if (isText === false) {
        let data:number = children
    }
}

TypeScript cannot tell that if (isText===true) children can only be of type string. Instead TypeScript assumes that children can be both of type number and string unaffected by the if condition.

Note: This is a oversimplified example to keep the code snipped short and clean. IRL you could use it in more complex cases, where it makes proper sense to use such a feature.

What do you want to use this for?

Being able to also destructure objects which may be of different types.

What workarounds are you using in the meantime?

Instead of destructuring the object and access the properties individually, I have to use the object and access its properties.

export function Eingabefeld(props:(
    {
        isText: true,
        children:string
    } | {
        isText: false,
        children:number
    }
)) { 
    if (props.isText === true) {
        let data:string = props.children
    }else if (props.isText === false) {
        let data:number = props.children
    }
}

Or use two destructuring assignment after the "if"-statement.

export function Eingabefeld(props:(
    {
        isText: true,
        children:string
    } | {
        isText: false,
        children:number
    }
)) { 
    if (props.isText === true) {
        let {children} = props
        let data:string = children
    }else if (props.isText === false) {
        let {children} = props
        let data:number = children
    }
}

What shortcomings exist with current approaches?

Simply more code needs to be written. When wanting to use destructuring assignments, two or more identical destructuring assignments need to be written and the alternative is to access the property from the object, requiring repeating the objects name a bunch of times, making the code more bloated in either way.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions