Repository: TypeScript
Issue: Keyword for inferring a new type from destructured parameters
Labels: Suggestion,Awaiting More Feedback

### 🔍 Search Terms

```
destructuring, destruct, infer destruct, infer destructuring, function destruct, function destructuring
```

Issue https://github.com/microsoft/TypeScript/issues/42419 (+ https://github.com/microsoft/TypeScript/issues/48220) discusses changing the current behavior of TypeScript to address the same underlying issue.

_My proposal is different as it introduces a new explicit language feature and does not change any current behavior._

I also found https://github.com/microsoft/TypeScript/issues/7576. The essence here is that they want some sort of shorthand for destructured parameter types.

_I think this is vaguely related to my proposal since it addresses a way to do that—it touches on a similar pain point._

### ✅ Viability Checklist

- [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 our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals

### ⭐ Suggestion

Let's introduce a feature that allows for TypeScript to infer a new type from destructured function parameters.

To conceptualize this idea, I'm introducing a new keyword called `from` which can be used after `:` when destructuring a function parameter:

```typescript
type Person = { first: string, last: string, age: number };

const isAdult = ({ age }: from Person) => age > 18;
```

This declares that `typeof isAdult` is `(person: Pick<Person, "age">) => ...`  instead of `(person: Person) => ...` meaning that any object matching `{ age: number }` can be passed in as a parameter.

You _could_ also potentially do this when destructuring a local variable, though, I struggle to see its usefulness:

```typescript
const { age, first }: from Person = person;
```

I'm not even sure whether this should be legal.

### 📃 Motivating Example

We often use destructuring in functions, because it helps us stay DRY:

```typescript
type Person = { first: string, last: string, age: number };

const formatName = ({ first, last }: Person) => `${first} ${last}`;
const isAdult = ({ age }: Person) => age > 18;
```

I think this is good practice and a sensible thing to include in your company style guide.

But if we look critically at the above snippet, we can see that the signatures for both `formatName` and `isAdult` are lying about their implementation. They (quite excessively) declare that they need _all_ properties from `Person` when they actually only need a few. And rightly so: I have explicitly declared that by writing `: Person`, but my intention here was actually to be able to pass any object that matches `{ age: number }` into `isAdult` (for example).

To solve this, I have to jump through some hoops, either like this …

```typescript
type Person = { first: string, last: string, age: number };

const isAdult = ({ age }: Pick<Person, "age">) => age > 18;
const formatName = ({ first, last }: Pick<Person, "first" | "last">) => `${first} ${last}`;
```
... _or_ the inverse:

```typescript
type Named = { first: string, last: string };
type Aged = { age: number; }
type Person = Named & Aged;

const formatName = ({ first, last }: Named) => `${first} ${last}`;
const isAdult = ({ age }: Aged) => age > 18;
```

However…

… the first solution is noisy and un-DRY since have to write the "pick part" twice: first for the destructuring itself, and then for the `Pick` type. Note: this effect is greatly exacerbated as the number of properties of a type increases, so this example is quite tame in that regard.

… the second solution (workaround?) feels too verbose for my use case (there's too much detail), I have no intent of re-use for the `Aged` or `Named` type. If the `Person` type comes from a third-party library (or another source that I don't control, e.g. Prisma), then this option is out of the question entirely as I can't "build up" my own type from smaller fragments (i.e. `Person = Aged & Named`).

This means that the first solution is often the only viable option—and it just isn't a great experience.

So—with the addition of the `from` keyword (or something similar), this headache is entirely relieved! It would make it much more convenient to declare the explicit requirements of a function to effortlessly make your code more expressive.

### 💻 Use Cases

> 1. What do you want to use this for?

This would have great utility in React components where you just want to pick a few props out of e.g. `ButtonProps` from `@mui/material/Button`:

```ts
function FooterButton({ color, href, children }: from ButtonProps)
```

However, I see many use cases for this: Anywhere where you need more generically defined function type signatures without having to create a new explicit type or use `Pick`/`Omit`.

> 2. What shortcomings exist with current approaches?

You need to manually use `Pick`/`Omit` or break types into smaller (often hard-to-name) types and compose them later on, or just live with the "excessive" type definitions.

4. What workarounds are you using in the meantime?

The above 👆