Repository: TypeScript
Issue: Improve `Array.from(tuple)` and `[...tuple]`
Labels: Suggestion,In Discussion,Domain: lib.d.ts

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Please read the FAQ first, especially the "Common Feature Requests" section.

-->

## Suggestion

<!-- A summary of what you'd like to see added or changed -->

`Array.from(tuple)` and `[...tuple]` should preserve individual types that made up tuple.

## Proposal

### `Array.from` (Simple)

Add this overload to `Array.from`:

```typescript
interface ArrayConstructor {
  from<T extends any[]> (array: T): T
}
```

[demo 1](https://www.typescriptlang.org/play/#src=interface%20ArrayConstructor%20%7B%0D%0A%20%20%20%20from%3CT%20extends%20any%5B%5D%3E%20(array%3A%20T)%3A%20T%0D%0A%7D%0D%0A%0D%0Aconst%20a%3A%20%5B0%2C%201%2C%202%5D%20%3D%20%5B0%2C%201%2C%202%5D%0D%0Aconst%20b%20%3D%20Array.from(a)%20%2F%2F%20Type%3A%20%5B0%2C%201%2C%202%5D)

**Caveats:**

* The above definition preserves everything including unrelated properties that do not belong to `Array.prototype` whilst actual `Array.from` discards them. (for instance, if input has `foo: 'bar'`,  output array will also has `foo: 'bar'`).

### `Array.from` (Complete)

Fix above caveats.

```typescript
interface ArrayConstructor {
  from<T extends any[]> (array: T): CloneArray<T>
}

type CloneArray<T extends any[]> = {
  [i in number & keyof T]: T[i]
} & {
  length: T['length']
} & any[]
```

[demo 2](https://www.typescriptlang.org/play/#src=interface%20ArrayConstructor%20%7B%0D%0A%20%20%20%20from%3CT%20extends%20any%5B%5D%3E%20(array%3A%20T)%3A%20CloneArray%3CT%3E%0D%0A%7D%0D%0A%0D%0Atype%20CloneArray%3CT%20extends%20any%5B%5D%3E%20%3D%20%7B%0D%0A%20%20%20%20%5Bi%20in%20number%20%26%20keyof%20T%5D%3A%20T%5Bi%5D%0D%0A%7D%20%26%20%7B%0D%0A%20%20%20%20length%3A%20T%5B'length'%5D%0D%0A%7D%20%26%20any%5B%5D%0D%0A%0D%0Aconst%20a%3A%20%5B0%2C%201%2C%202%5D%20%3D%20%5B0%2C%201%2C%202%5D%0D%0Aconst%20b%20%3D%20Array.from(a)%20%2F%2F%20Type%3A%20CloneArray%3C%5B0%2C%201%2C%202%5D%3E%0D%0Aconst%20l%20%3D%20a.length%20%2F%2F%20Type%3A%203%0D%0Aconst%20%5Bx%2C%20y%2C%20z%5D%20%3D%20a%20%2F%2F%20Type%3A%20%5B0%2C%201%2C%202%5D%0D%0Aa.map(x%20%3D%3E%20x)%20%2F%2F%20(0%20%7C%201%20%7C%202)%5B%5D)

### Spread operator

```typescript
declare const tuple: [0, 1, 2] & { foo: 'bar' }

// $ExpectType [string, string, 0, 1, 2, string, string]
const clone = ['a', 'b', ...tuple, 'c', 'd']
```

Note that `typeof clone` does not contain `{ foo: 'bar' }`.

## Use Cases

<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->

* Clone a tuple without losing type information.

## Examples

<!-- Show how this would be used and what the behavior would be -->

### Clone a tuple

```typescript
const a: [0, 1, 2] = [0, 1, 2]

// $ExpectType [0, 1, 2]
const b = Array.from(a)
```

### Clone a generic tuple

```typescript
function clone<T extends any[]> (a: T): T {
  return Array.from(a)
}
```

## 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. new expression-level syntax)