Skip to content

Recursive Mapped Type Narrows Branded Property to Never #35992

Closed
@abirmingham

Description

@abirmingham

TypeScript Version: nightly, 3.7.2, 3.6.3, 3.5.1 (issue occurs in all versions except 3.5.1)

Search Terms:
recursive, mapped, brand, branded, nominal

Code

/**
 * A simplified version of redux@4.0.5's `PreloadedState<S>`. Simplified to
 * produce a minimal repro.
 */
export type PreloadedState<S> = {
    [K in keyof S]: S[K] extends object ? PreloadedState<S[K]> : S[K]
};

export type Branded<K, T> = T & {
    __BRAND__: K; // (or K & void)
};

type InitialState = PreloadedState<{
    someString: Branded<'Foo', string>;
}>; // evaluates to { someString: never }

Expected behavior:
InitialState is typed as { someString: Branded<'Foo', string> }.

Actual behavior:
InitialState is typed as { someString: never }.

Playground Link:
Here

Context:
This issue affects usage of redux@4.x.x when calling Redux.createStore. Redux.createStore uses a recursive mapped type for the preloadedState. In my case, PreloadedState<S> is incompatible with S, because PreloadedState<S> contains never types and S does not.

Metadata

Metadata

Assignees

No one assigned

    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