Skip to content

Wrong type inferred for nested union #20280

Closed
@dwickern

Description

@dwickern

TypeScript Version: 2.7.0-dev.20171126

Context: a method for ember.js which extracts the value from some path, e.g.

get({ foo: { bar: { baz: 'hello' }}}, 'foo', 'bar', 'baz') // returns "hello"

Each value in the path might be some plain object T or a Wrapped<T> (in which case we return the underlying T)

Code

Typescript can infer the returned type using a union:

// working example
interface Wrapped<T> { value: T }

type Props1<T> = {
    [K in keyof T]: Wrapped<T[K]> | T[K];
}

declare function get1<T, K1 extends keyof T>(obj: Props1<T>, k1: K1): T[K1];

declare const obj1: { a: string };
const v1: string = get1(obj1, 'a'); // works

declare const obj2: { a: Wrapped<string> };
const v2: string = get1(obj2, 'a'); // works

However, it no longer works when the union types are nested:

// non-working example
type Props2<T> = {
    [K in keyof T]: Wrapped<Props1<T[K]>> | Props1<T[K]>
};

declare function get2<T, K1 extends keyof T, K2 extends keyof T[K1]>(obj: Props2<T>, k1: K1, k2: K2): T[K1][K2];

declare const obj3: { a: { b: string } };
const v3: string = get2(obj3, 'a', 'b'); // works

declare const obj4: { a: Wrapped<{ b: Wrapped<string> }> };
const v4: string = get2(obj4, 'a', 'b'); // TS2345:Argument of type '"b"' is not assignable to parameter of type 'never'.

If I eliminate the right side of the union from Props2, then the obj4 example works

type Props2<T> = {
    [K in keyof T]: Wrapped<Props1<T[K]>> //| Props1<T[K]>
};

The obj4 example should pick the left side of the union to begin with

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions