Skip to content

Difference in behaviour with mapped types between concrete and generic types. #19509

Closed
@DylanRJohnston

Description

@DylanRJohnston

Trying to give better types to the redux library. Came across this issue. The issue appears to be the reindexing via keyof A at the end.

TypeScript Version: 2.7.0-dev.201xxxxx

Code

type Actions = {
  INCREMENT: { x: number }
  DECREMENT: { y: string }
}

type Concrete = {[K in keyof Actions]: {type: K} & Actions[K] }[keyof Actions]

type Generic<A> = {[K in keyof A]: {type: K} & A[K] }[keyof A]

type GenericConcrete = Generic<Actions>

Expected behavior:
Concrete and GenericConcrete have the same type

Actual behavior:
Concrete has the correct type

type Foo = ({
    type: "INCREMENT";
} & {
    x: number;
}) | ({
    type: "DECREMENT";
} & {
    y: string;
})

GenericConcrete has the wrong type

type Foo = ({
    type: "INCREMENT" | "DECREMENT";
} & {
    x: number;
}) | ({
    type: "INCREMENT" | "DECREMENT";
} & {
    y: string;
})

Unless I'm missing some kind of constraint on A in the Generic case that Typescript is able to use in the concrete case to work out the types correctly?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Needs More InfoThe issue still hasn't been fully clarified

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions