Microsoft/TypeScript

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

Open

#50,139 建立於 2022年8月2日

在 GitHub 查看
 (14 留言) (3 反應) (0 負責人)TypeScript (6,726 fork)batch import
BugDomain: check: Control FlowHelp Wanted

倉庫指標

Star
 (48,455 star)
PR 合併指標
 (平均合併 6天 17小時) (30 天內合併 9 個 PR)

描述

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.

貢獻者指南