Repository: TypeScript
Issue: Array of object unions not working as expected
Labels: Needs More Info

### 🔎 Search Terms

"array of object unions", "array union narrowing", "union narrowing", "object union operator in"

### 🕗 Version & Regression Information

- This changed between versions `5.2.2` and the latest `5.6.2`


### ⏯ Playground Link

[Playground](https://www.typescriptlang.org/play/?#code/JYOwLgpgTgZghgYwgAgKLigTwEJwM4oDeAUMmcgPQBUVp5yVyAKpgA4qgwD2AdH3eSoUByMGwgB+AFzIA5ABMI8AK4AbMLOQAfOYoSq4UOGGBcQmkdVr0GyAPLKwrR8gBG+DiG58eIhsPouR2cwaWQ8MChQAHNLGj9GADEuKABbYzcPZE5efhshEW404zCIqJBY+isE5AA5OFSUdwJsr1zffIDyEAbJGTKY4gBfYmJQSFhEFAAFVWVo0DwAESU4NTBkEir4-LQ8V2VgVXlkVjmFkFbvPPpGGoABRRV1ZGUQJ9AIeQSusgh9w7HMIAJQgCBS8gAPAMKgAaV4gADWIC4AHcQAA+YajcbQeBINAYTArZ4bCAAD0g7zwhMiOCyW3I1V2AEkQCFkE81i8cj4fiJQCF+pFBttrLc6r1Oat1ld2vz6D1GqURRU4uLBMhZvNFtLSXK+bsHlzZW8PiAvgryGcdSA8GFtRdljL1NixuA8VMtedFit9IZjKZLoyyMyJUswDSbRcDTdNcaXRszUpPt9OiJ5JGQWCIdDVdF4W9kWjMW7cZMCeg6X6DEYTGZkBSqfIaVWsLgWiHKDtw2Da4GG7y42QCvQ9P36yBheVKkye5rHbrxwHJ7GOhKE-rkzBU1ayNHFg6fXaayug26xOxaVF-nZWJOaQBea-ExPaF+nuvn0bgu0bLj3kGeAyG2wC3oBZh4AA2gAusgz5QeqNQABJmP8YCqJgyAABbQCgLLIKiQTHI25LsAgGwsOwADKCBRPeohcG4KB4OkUBkii8zYTUYBMWsvHpCYCBwKomFXDA0CiOINLNF8yANmYYlocgUAQAAjocqknKwUAAdAYjIAAFAABoKjjGQAlDUcDvKcwAIIiNLglAqkUa0Ez4v8yA2ScImqNKeB0cAEF2m4LgEcJlz4HgyiNDx2EZGA2HADSKXIKkKQoOCqRnBSogJZcwAbHgQS2Xumx+OQZlgDIsg8BQeBQAgFCgIo5I8JGsjwpVZBBE4ji1fV8gpWALXvBSPCpAAVngXXID1lAUMgKIBUFIXyVA3mOFw2W5ZA802Nax7AZsjYAkc8gyIQQzIEMsILRQS0rYogX0auKRbbxu2qBA+0LUqEC1SaLwA11C2XoDuiJrIIh3aMYo1AAgqoJXedEcCgPJIBKRaKnqZpck6Xp7FYcZy5fmYmio0VhHEScrgoCA9kcDAB0SlREC0W9yDgmovnbYJ9l+VhnCSUlKCothXA-e5noEs5rkYZgPxs2QXZjn2Z5mINDVNRQEN4B1s33YdvXBANchDSN+vSWNbU8PIRtg6byBFIJtX-Kkzum49y1MS9a3vZt-E7VwOU-X9LsHnaV2cpGV03XDLu+89-yB0GG2faH4e-Sg-29EDmsU5coMm6bEOF-6xcw-QIwwaMzKMARBCGAguG+cgqhcP+lzi8tv3ebZwmNN5dFcHgNJJWlFINLlOFgE4wGPREiCIlwABueJd6iPDZRQGnoUBFAAOwAMwAIwAKyXwATAAbOfFBS6iAC0vEvz0Lloi-8gli-cAv2iBAC0UQEBv3EC-WS8gX5mBga4KaYIwAvyJuwEm4D2CkEYJLPCyBjJTWEqoAAXmTNOUQGY0h8sgBYm8KGXBnjnHCaJGLLUMLpVE+UUAG0yAQE4Cl4GIOQIiCAmA8DdVsAcDYBFojKH+JPZKqU5FZWUC5YBGwiJQERDEcI0tHAZ0ob-f45g1EpERK0byokeYeFEQdJu5jUZEXGptZ+zDf7ZDUbhXuuFBHCNOLpVBBk0oAUnCJQeJwUTFXIsAHcclMZcH4RRCQmDhDEAhmgSkRgKJ2BANMPxkImDwgANKkWbDSIRmAuCs3ycgAAahieCIgmDFOAS2BExZ0TIAkDUpp1JmBQQKXBRJ9BCDICgtMMxZSKnMBgjIMZTZmk0iKZ0pgoy4IADIukyGWdMOCIx6AyAtJvTa+yICHNGKk0C4EHzTGgDkgC8E0mREQGALJtzWCQjbK+Uk8JZAQzmgoaGdSdAPIyc87JuSPmfgHCAb5vzvnkyhbIOpowYBvAohnc0EAADCZgdzREMkEoCIEMBgTwHeK5Ny-GwQskSkUlygLXKgK82CFV6CqTAMoy4BLILDHmsQDF2KvDADxYhIZC1qo60as1VqE1OpiNNn1IUlsKDDQiHbCa01jYLWjidYZ-wDgXQTrdMuh0AaF31KXcG4gzXcg0LDY1LLTbwsnBKvWBsnb2sCObGqSqVWjQNmq9qjtZULTdsYD2rFvaHW1bHTMOrE4eu6AXKGVcoUsMaJGmwFdk0TiDDXcgScmRLQMTScJtMNHZFZsZCGxlsglu7nqXcoqXbiqVZKgN7rVY2AVRbOqyrrbSvahqjN9Bo2nT1YCS6mx4350aNa2UFra73RghZIAA)

### 💻 Code

```ts
interface EntryBase {
    /**
     * Type info...
     */
    type?: 'default' | 'declaration' 
    /**
     * Output base info...
     */
    output?: string
    /**
     * Format base info...
     */
    format?: string
    /**
     * Name base info...
     */
    name?: string
}

interface PluginsDefault {
    /**
     * Esbuild plugin info...
     * 
     * @default undefined
     */
    esbuild?: Record<string, unknown>
}

interface EntryDefault extends EntryBase {
    /**
     * Input default info...
     */
    input: string
    /**
     * Name default info...
     */
    name?: string
    /**
     * Plugins default info...
     * 
     * @default undefined
     */
    plugins?: PluginsDefault
}

interface PluginsDeclaration {
    /**
     * Dts plugin info...
     * 
     * @default undefined
     */
    dts?: Record<string, unknown>
}

interface EntryDeclaration extends EntryBase {
    /**
     * Declaration info...
     */
    declaration: string
    /**
     * Plugins declaration info...
     * 
     * @default undefined
     */
    plugins?: PluginsDeclaration
}

type EntriesOptions = EntryDefault | EntryDeclaration


const options: EntriesOptions[] = [
    /**
     * Honestly here I would expect TypeScript to be smart enough
     * to automatically inffer types based on only one required property (`input`)
     * and picks correct interfaces and all descriptions but I can assume
     * that this is more complex than it sound 
     */
    {
        input: './src/index.ts', 
        output: './dist/index.mjs', 
        // no description or autocomplete 
        plugins: { esbuild: {} },
        // no description or autocomplete 
        name: 'default name',
        type: 'default'
    },

    /**
     * Also again only one required property `declaration' so it would be nice if 
     * TypeScript could automatically infer the whole interface correctly
     */ 
    {
        declaration: './src/types.ts',
        output: './dist/types/index.d.ts',
        format: 'esm',
        // no description or autocomplete 
        plugins: { dts: {} },
        // no description or autocomplete 
        name: 'declaration name',
        type: 'declaration'
    }
]

/**
 * I searched a lot on the net and came across this example https://stackoverflow.com/questions/73155261/how-to-narrow-down-a-generic-type-based-on-object-property-type
 * where `jcalz`describes and gives an example how to narrow the types based on object keys, 
 * but I guess this is the current working solution and doesn't work in all cases, 
 * I also wonder how to do it when the key property is optional and not specified in object?
 */

type ExtractOnProp<T, K extends keyof T, V> =
    T extends unknown ? V extends T[K] ?
    { [P in keyof T]: P extends K ? T[P] & V : T[P] }
    : never : never

type EntriesOptionsPerProp = ExtractOnProp<EntryDefault, 'type', 'default'> |  ExtractOnProp<EntryDeclaration, 'type', 'declaration'> 

function defineConfig(options: EntriesOptionsPerProp[]): EntriesOptionsPerProp[] {
    return options
} 

defineConfig([
    {
        input: './src/index.ts', 
        output: './dist/index.mjs',
        plugins: { esbuild: {} },
        name: 'default name',
        type: 'default'
    },
    {
        declaration: './src/types.ts',
        output: './dist/types/index.d.ts',
        format: 'esm',
        plugins: { dts: {} },
        name: 'declaration name',
        type: 'declaration'
    },
    // does not work if `type` is not defined
    {
        input: './src/index.ts', 
        output: './dist/index.mjs',
        plugins: { esbuild: {} },
        name: 'default name',
    },
])
```

### 🙁 Actual behavior

Hi, as discussed in previous issue [#56082](https://github.com/microsoft/TypeScript/issues/56082) and the merged [PR](https://github.com/microsoft/TypeScript/pull/56088), it seems like this area could use some internal improvements.

When we have multiple interfaces that extend the base interface, then the types are not picked up correctly when defining a new array of object unions.

Also, properties from the object do not get description information or offer correct auto-completion which can be confusing.

### 🙂 Expected behavior

I expect it to offer the correct auto-completion for each object and give the right information when I hover over a property to see the type or description of what that option does.

### Additional information about the issue

I mentioned some examples and expectations of behavior in the playground.