Repository: TypeScript
Issue: Target of object rest destructuring should allow an implicit index signature if its source does
Labels: Suggestion,In Discussion,Experimentation Needed

# Suggestion

## 🔍 Search Terms

destructuring assignment, object rest, implicit index signature,


## ✅ Viability Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

From a [comment](https://github.com/microsoft/TypeScript/issues/42021#issuecomment-1048351286) on the related #42021:

[Implicit index signatures](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html#implicit-index-signatures) are only allowed for "objectish" types that are either object literal types or inferred from an object literal value.  They are not permitted for `interface`s or the instance type of `class`es, as discussed in #15300.

When using [rest in object destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#rest_in_object_destructuring) to copy properties from a source object to a new target variable, the new variable is not considered to be "objectish" even if the source expression is.  This is surprising as shown by [this Stack Overflow question](https://stackoverflow.com/questions/71179712/typescript-difference-between-original-object-and-spreaded-object) and various examples in #42021.   

The proposal here is that the type of the new variable should inherit "objectishness"  from the initializing expression.  

## 📃 Motivating Example

Consider the following example demonstrating the current behavior:

```ts
const foo = (x: Record<string, unknown>) => void 0

const x = { a: 0 }
// const x: { a: number }
foo(x); // okay, `x` is granted an implicit index signature

const { ...y } = x;
// const y: { a: number }
foo(y); // error, `y` is denied an implicit index signature
//  ~ <--  Index signature for type 'string' is missing in type '{ a: number; }'
```
[Playground link](https://www.typescriptlang.org/play?#code/MYewdgzgLgBAZiEMC8MAUAPAXDASgU1ACcATAHmiIEswBzAGhgFcwBrMEAdzAD4BKFDxgA3EFRIwADAFgAUHNCRYGFDADeMAIY5JMAL5yA9IZiLoMbOq04wTALYAjfEX1yEITHwDcMYzBCsmgCe6FR2AA4ANlTAVLA0JPgqEFS0YJpQTET4fHIK4OYaAHQlIXqqGF5GJmawQTga2jC2js6usu5oQd6+Js5EIC5oHDBhUTFxo2CJyanpmdm5sn4wAH4wZAC0mzAwAJLTSTApaRlZ+PCDMFBB4RcA5JQ0tPejEDB2VBApdFPXtw9GjZ7E4iD49Pc8rIgA)

It is surprising that while `y` is a copy of `x` and the types of `x` and `y` are seemingly identical, you are allowed to call `foo(x)` but prohibited from calling `foo(y)`.  The suggestion here is to make it so `foo(y)` succeeds if and only if `foo(x)` succeeds.

## 💻 Use Cases

* This helps TypeScript more fully support rest destructuring assignment `const {...y} = x` as an alternative to `const y = Object.assign({}, x)` for copying properties into a new object, which is the current workaround for things like this (modulo define-vs-set semantics and other things that go bump in the night).  

* This also helps support the removal of some properties `const { a, ...y } = x` while maintaining "objectishness", which currently doesn't have a nice and simple workaround.