Skip to content

Types of optional arguments not inferred correctly #56545

Closed as not planned
Closed as not planned
@lsnow99

Description

@lsnow99

🔎 Search Terms

"optional" "arguments" "inference" "generic" "narrowing" "parameters"

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about optional parameters

(tested on latest minor version of v3, v4, and v5)

⏯ Playground Link

https://www.typescriptlang.org/play?target=99&jsx=0&ts=5.3.2#code/PTAECECcHsGsFMB2p4A8CGBbADgG3qAO4CWALgBagDG0iAJmcberqKQJ7bwDOAULwDMAroiqkmyTOwBiIsRIAUqAPwAuUIiGYARvEgBKdRy7QBoVClSkkdbqBF14A4onh1Qy0N1KQXAc1B1TR09UABvXlAo0GIzJVAAXiT7eicXN31wyOicmkRvUAAvRPNQEFAASVJQWERoQjtjeFNSpISUx2dXd3I9eAAaUG0hau9iXFZCdERSRuhQSHhSIUhkdA0tXUhsnKjygGFoR1ABaEgiXuQLYjs60aFsPGI3Hd3F5dXQACIAFU4CACCXwA3K8AL4oXDcAgRXbRA5HAinc6ES6lG5eB5PF5wqLvFZXUAAKlAACZgWUwABRDA4fCDdjQITUaYLJYE0DrBgCAR9GZsf6gXqLcG8MH8PIFRbcIS4UgARnU3l8iAC7SkslE4loCn0FJy5QqAHJ3GguGI2OQMbQCKR5roBVx3Og7Otlf5eJLqtLZaRSUFNqF1TI5NrEAoAKx6g1gH5Wuw2x08ahnRZiXDsfj8coABXQkHELAzRDOsH8liweHgEtoBWw+cLE3YAHVS+X2gpOuhfQA1FhCeBqDYhAyJAB8WSisVAnac3blfdwA8SyQcaW6mVh0Xxny+dytqq+2Qh8ChMNeO+QXd7-erUXF4t45QAEn0htAKJzFknnbdA+cAB8vB8fxBlRYgqEoDF0GqfAXWqGhIDTUhBmGao7k5OxlVoAIXRiBCmVwdxdE9WtqjQeUSnrAtiCLFs21VBR5X0Uj8nI1BSSohtaKbVtIDLRiWKzcooDgJAKzpatPVwF07BzAAeAAtCdYS9SAhDEM4Z0KdRFM3bJJWgfAADpcGgPwFEKFjQAffgmlAH4SjCTl1HlR8vVAaBsDDFgSnkgANEofjHWcBHnUhFwHId-MyBIVOyadQvCyKCDaDp1wySdt3ZT5XEIUAFMcoC1y6NwQpK9I6GsmzIWhLK8Ry5A8oK+SitAfyQuvBdb2q2ynzAcAP0oFoKB4Ah81tf5fxatqKu6MdjNAfrKkcOjBlGk5iEgApE24chCOIyanUwpbc1a0AgOCLYJ2mdwNuhPJ3ETJpf2WwqLvS0q6AW0AASheZ0CoKh4G89BtHwEtZUO5btCGoZ4HLF6TveoCOo+lHPsqsdWIKBUSi8nzcCYgAWFiPL9fHvIkFhdSAA

💻 Code

// Broken example with conditional types

function myFunction(x?: number): typeof x extends undefined ? string : number {
    if (x === undefined) {
        const z = x // It knows typeof x === undefined here, but still wants to return a number
        // Code for when x is not supplied
        return "Type A";
    } else {
        // Code for when x is supplied
        return x * 2; // Example, you can return a different type here
    }
}

const result1: string = myFunction();     // I'd expect this one to be typed as a string
const result2: number = myFunction(5);    // This one types correctly



// Partially working example

const partiallyWorking = (defaultValue?: number) => {
  if (defaultValue === undefined) {
    return "nothing"
  } else {
    return defaultValue
  }
}

// Here both are typed as number | string, which is at least correct, but not as strong as it could be
const ex1 = partiallyWorking(1)
const ex2 = partiallyWorking()



// Broken example

class P<Z> {
 constructor (z: Z) {
  console.log(z)
 }
}

type T = { a: 1}

const optional = <X = T>(defaultValue?: X) => {
  if (defaultValue === undefined) {
    return new P<T | undefined>(undefined)
  } else {
    return new P<T | X>(defaultValue)
  }
}

// Both of these are typed as P<T | undefined>. 
// Ideally, the first one should be typed as 
// P<T | number> and the second one typed as
// P<T | undefined>. Also acceptable would be
// both being typed as P<T | X> | P<T | undefined>
const t1 = optional(14)
const t2 = optional()

🙁 Actual behavior

Specifically in the third case, the return type was incorrectly narrowed to the wrong value.

🙂 Expected behavior

The function's return type should either be the union of the two possible return cases, or it should be narrowed based on the value of the optional argument.

Additional information about the issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions