Repository: TypeScript
Issue: New type param modifier to allow for partial inference based on signature declaration
Labels: Suggestion,In Discussion

# Suggestion

## 🔍 Search Terms

partial inference modifiers type parameters

## ✅ 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

Type inference is a powerful tool but for certain scenarios it suffers from a usability issue - it's all or nothing and doesn't allow for "partial application".

There are two angles here:
1. users sometimes would like to partially apply the type arguments list
2. library authors would like to accept partial type arguments list

When it comes to the first one there is already an open proposal for it [here](https://github.com/microsoft/TypeScript/issues/26242) and even a PR implementing it [here](https://github.com/microsoft/TypeScript/pull/26349). Based on reactions below both of those I think it's fair to say that it's a highly requested feature.

However, even if that feature would get its way to the language it would still suffer from some usability issues for the mentioned second use case. The problem is that this feature would require an explicit **opt-in** by the user to leverage this feature. I think that's an *acceptable* tradeoff for library authors - we certainly wouldn't be super picky about it if that feature would land. 

I think though that this could easily be improved by allowing a special type parameter modifier - like `preferinfer` or just `infer`:
```ts
declare function get<T, preferinfer K extends keyof T>(obj: T, key: K): T[K]

// `T` provided as `User`, `K` inferred as `name`
const res = get<User>({ name: 'Andarist', age: 32 }, 'name') 
res // string
```

Both use cases are very much related but I feel like they are orthogonal as one can exist without the other. This proposal focuses only on the second use case. A draft implementation for the feature can be found [here](https://github.com/microsoft/TypeScript/pull/52241).

## 📃 Motivating Example

In XState we accept a couple of type arguments but we'd also like to additionally perform some additional inference/validation based on the received `config` argument. It's a JSON-like schema:
```ts
declare function createMachine<
  TEvent extends { type: string },
  preferinfer const TConfig extends MachineConfig<TEvent>
>(config: TConfig): StateMachine<TConfig, TEvent>

type MyEvents = { type: 'INC' }

createMachine<MyEvents>({
  initial: 'foo',
  states: {
    foo: {
      on: {
        INC: 'bar', // should be allowed
        OTHER: 'bar', // should be an error
      }
    },
    bar: {}
  }
})
```

This would be especially useful for us in combination with the recently introduced `const` type parameters.

At the moment we have to resort to this, rather silly, workaround:
```ts
createMachine({
  types: {
    events: {} as MyEvents // workaround here
  },
  initial: 'foo',
  states: {
    foo: {
      on: {
        INC: 'bar', 
        OTHER: 'bar',
      }
    },
    bar: {}
  }
})
```

Drawbacks of this approach:
- this puts some unnecessary pressure on TS to infer things that we don't really want to infer. They are meant to be explicitly given by the developers.
- the `types` also become part of the inferred `TConfig`
- it's easy to accidentally infer `TEvent` from locations that shouldn't be used as inference sources. A rogue `any` somewhere added to inference candidates might implicitly deopt all locations. We have to use `NoInfer` trick to avoid this

Another workaround for this issue is to change the API, use factory functions to "bind" explicit type parameters to the returned function. This alters the API though and I don't think that's really a suitable workaround when better alternatives could exist.

IIRC, Redux Toolkit also uses a similar pattern in its types to "accept an explicit type" for `TState`. And I distinctly remember that Tanner from Tanstack would give a lot for a feature like this (perhaps this would be more useful for Tanstack Table than Tanstack Query). I'm pretty sure that a ton of OSS library authors would just love, love to see a solution for this to land in some shape.