Skip to content

Destructuring issue after removing a keyed propertyΒ #57614

Closed as not planned
Closed as not planned
@michaeljota

Description

@michaeljota

πŸ”Ž Search Terms

destructure omit

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about
    • 3.x
    • 4.x
    • 5.x

⏯ Playground Link

πŸ’» Code

Updated example:

declare function getId<Model, Id>(model: Model): Id;

function removeRecord<
  Model extends object,
  Id extends 'foo' | 'bar'
>(stateModels: Record<Id, Model>, model: Model): Record<Id, Model> {
  const id = getId<Model, Id>(model);

  const { [id]: deletedEntity, ...models } = stateModels;

  return models;
};

Original Example:

type ModelKey = string | number;
type ModelsWithId<Model, Key extends ModelKey> = Record<Key, Model>;

declare function getIdWithKey<Model, Key>(model: Model): Key;
function removeRecordWithKey<
  Model extends object,
  Key extends ModelKey
>(stateModels: ModelsWithId<Model, Key>, model: Model): ModelsWithId<Model, Key> {
  const id = getIdWithKey<Model, Key>(model);
  const { [id]: deletedEntity, ...models } = stateModels;

  return models;
};

πŸ™ Actual behavior

And error is thrown in the return statement:

Type 'Omit<ModelsWithId<Model, Key>, Key>' is not assignable to type 'ModelsWithId<Model, Key>'.
  Type 'Key' is not assignable to type 'Exclude<Key, Key>'.
    Type 'ModelKey' is not assignable to type 'never'.
      Type 'string' is not assignable to type 'never'.(2322)

The result type is an empty object

interface EmptyRecord {}

function removeRecordWorking<
  Model extends object,
  Id extends 'foo' | 'bar'
>(stateModels: Record<Id, Model>, model: Model): EmptyRecord {
  const id = getId<Model, Id>(model);

  const { [id]: deletedEntity, ...models } = stateModels;

  return models; // No errors
};

πŸ™‚ Expected behavior

No error should be thrown, because an object with a removed keyed property, should be equal to the same object.

Additional information about the issue

When you don't use a keyed property, the code is valid:

interface RemoveModel {
  id: string;
}

type ModelWithStringKey = Record<string, RemoveModel>;

function remove(state: ModelWithStringKey, model: RemoveModel): ModelWithStringKey {
  const id = model.id;

  const { [id]: deletedEntity, ...models } = state;

  return models;

};

The Playground link for "Original example" has different examples for more complex and simpler scenarios.

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