Skip to content

Given generic W extends { x: A | B | undefined } should be able to use keyof W['x'] to index w.x #17110

Description

@studds

TypeScript Version: 2.4.0 / nightly (2.5.0-dev.201xxxxx)

2.4.1 (playground)

Code

// A *self-contained* demonstration of the problem follows...

interface A { a: string; }

interface B {  b: string; }

interface W {
    x: A | B | undefined;
}

function fn2<W1 extends W>(w: W1, k: keyof W1['x']) {
    // issue 1: incorrect error: Type 'keyof W1["x"]' cannot be used to index type 'Partial<A> | Partial<B>'.
    // also correctly reports error: Object is possibly 'undefined'.
    w.x[k] = 'string';

    // this is fine, with the explicit type
    const x: W1['x'] = w.x;
    // issue 2: Should complain that w.x might be undefined
    x[k] = 'string';
}

// Inside the generic function, W1['x'] is unnecessarily and prematurely resolved to `A | B | undefined`, 
// causing the error to be incorrectly reported.
// The final type of W1['x'] and keyof W1['x'] should only be resolved when the function is called.
// This in fact works correctly already. 

// correctly infers type of param k, errors: Argument of type '"a"' is not assignable to parameter of type '"b"'.
fn2({ x: { b: '' } }, 'a');

// no error
fn2({ x: {  b: '' } }, 'b');

// k is correctly resolved to never: Argument of type '"a"' is not assignable to parameter of type 'never'.
let ambiguous: W = <W>{};
fn2(ambiguous, 'a');
fn2({ x: undefined }, 'a');

Expected behavior:

  1. Given a generic W extends { x: A | B | undefined } should be able to use keyof W['x'] to index w.x
  2. Should complain that w.x could be undefined after assigning to explicitly typed variable W['x']

Actual behavior:

  1. Errors unless you create a local variable with explicit type W['x']: const x: W['x'] = w.x;
  2. Does not complain that x could be undefined after assigning to explicitly typed variable W['x']

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Working as IntendedThe behavior described is the intended behavior; this is not a bug

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions