Skip to content

NonNullable is accidentally simplified away from generic index accessesΒ #50539

Description

Bug Report

πŸ”Ž Search Terms

defer, index access, index signature, nonnullable

πŸ•— Version & Regression Information

  • This somewhat changed between versions 4.7 and 4.8

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

interface StateSchema {
  states?: {
    [key: string]: StateSchema;
  };
}

declare class StateNode<TStateSchema extends StateSchema> {
  schema: TStateSchema;
}

// worked in 4.7 but perhaps accidentally
type StateNodesConfigCurrent<TStateSchema extends StateSchema> = {
  [K in keyof TStateSchema["states"]]: StateNode<TStateSchema["states"][K]>;
};

// this OTOH should work right now but it doesn't
type StateNodesConfigNew<TStateSchema extends StateSchema> = {
  [K in keyof TStateSchema["states"]]: StateNode<
    NonNullable<TStateSchema["states"]>[K]
  >;
};

πŸ™ Actual behavior

NonNullable disappears when computing getConstraintFromIndexedAccess. Essentially this type:

NonNullable<TStateSchema["states"]>[keyof TStateSchema["states"]]

gets simplified/distributed to

TStateSchema["states"][string] | TStateSchema["states"][number] | TStateSchema["states"][symbol]

As we might notice here - NonNullable is gone from here because of the simplification rules:

// (T | U)[K] -> T[K] | U[K] (reading)
// (T | U)[K] -> T[K] & U[K] (writing)
// (T & U)[K] -> T[K] & U[K]

The third case applies here so we end up with something like this

TStateSchema["states"][string] & {}[string] | TStateSchema["states"][number] & {}[number] | TStateSchema["states"][symbol] & {}[symbol]

In here, those {}[string | number | symbol] are just reduced to unknown and T & unknown gets reduced to T. So that's how NonNullable "disappears" here.

Note that even though T[number | symbol] is not valid for this T this indexed access is allowed based on this logic:
https://github.dev/microsoft/TypeScript/blob/488d0eebd0556fcc6e5f4cfc69c2ef7e5c2708ed/src/compiler/checker.ts#L16036-L16040

πŸ™‚ Expected behavior

NonNullable should be correctly retained/deferred in this case to preserve the correct constraint of the generic type.

Activity

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

Metadata

Metadata

Labels

Fix AvailableA PR has been opened for this issueNeeds InvestigationThis issue needs a team member to investigate its status.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions