Skip to content

TS2536 thown when using keyof on a property of a generic type as key #36631

@c-goldschmidt

Description

@c-goldschmidt

TypeScript Version: 3.8.0-dev.20200204

Search Terms:

  • TS2536
  • generic typing
  • keyof

Code

enum Switch {
    A = 'a',
    B = 'b',
}

interface ResultA {
    keyA1: number;
    keyA2: string;
}

type ResultB = number[];
type ResultType = ResultA | ResultB;

interface GenericBase {
    switch: Switch;
    value: ResultType;
}

interface GenericA extends GenericBase {
    switch: Switch.A;
    value: ResultA;
}

interface GenericB extends GenericBase {
    switch: Switch.B;
    value: ResultB;
}

type GenericType = GenericA | GenericB;

function getValue<T extends GenericType, K extends keyof T['value']>(result: T, key: K): T['value'][K] {
    // T = GenericA
    // T['value'] = ResultA
    // keyof ResultA = 'keyA1' | 'keyA2'

    // T = GenericB
    // T['value'] = ResultB
    // keyof ResultB = number | "toString" | [...]

    // unexpected: error TS2536: Type 'K' cannot be used to index type 'ResultType'.
    return result.value[key];
}

const a: GenericA = {switch: Switch.A, value: {keyA1: 1, keyA2: 'A'}};
const b: GenericB = {switch: Switch.B, value: [1, 2, 3]};

// no errors
console.log(getValue(a, 'keyA1'));
console.log(getValue(a, 'keyA2'));
console.log(getValue(b, 0));
console.log(getValue(b, 3));

// error TS2345: Argument of type '0' is not assignable to parameter of type '"keyA1" | "keyA2"'.
// => expected, and the compiler does know what keys can be used
console.log(getValue(a, 0));

// error TS2345: Argument of type '"keyA1"' is not assignable to parameter of type 'number | "toString" [...]
// => also expected
console.log(getValue(b, 'keyA1'));

Expected behavior:
As long as the correct keys are used, which is covered by TS2345, the index access should not raise an error.

Actual behavior:
TS2536 is thrown when compiling, altough the keys should be known due to the generic typing.

Playground Link: typescriptlang.org

Related Issues:

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions