Repository: TypeScript
Issue: Use-case for making weak-types / EPC more strict
Labels: Suggestion,Awaiting More Feedback

# Suggestion

## 🔍 Search Terms

exact types, epc, weak types, all optional properties

## ✅ Viability Checklist

My suggestion meets these guidelines:

* [ ] 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


Consider the following problem...

```ts
type Basket = { bananas: number, apple: number }
declare const updateBasket: (f: (state: Basket) => Partial<Basket>) => void

updateBasket(basket => ({ banana: basket.bananas + 1, apple: 10 }))
// oops didn't catch "banana" typo it should have been "bananas"
```

Imo this should be solved by implementing [exact types](https://github.com/microsoft/TypeScript/issues/12936) but given Ryan said in [this](https://github.com/microsoft/TypeScript/issues/12936#issuecomment-284590083)...

> [...]
> For the most part where people want exact types, we'd prefer to fix that by making EPC smarter. A key area here is when the target type is a union type - we want to just take this as a bug fix (EPC should work here but it's just not implemented yet). 
> [...]
> ## Summary: Use Cases Needed
> Our hopeful diagnosis is that this is, outside of the relatively few truly-closed APIs, an [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) solution. Wherever possible we should use EPC to detect "bad" properties. So if you have a problem and you think exact types are the right solution, please describe the original problem [...]

... hence I'm filing this issue (not sure if it's a bug or a feature). Moreover there's also an involvement of a "weak type" here (namely the `Partial<Basket>`) so this part of that comment from Ryan also applies...

> Related to EPC is the problem of all-optional types (which I call "weak" types). Most likely, all weak types would want to be exact. We should just implement weak type detection (https://github.com/microsoft/TypeScript/issues/7485 / https://github.com/microsoft/TypeScript/pull/3842); the only blocker here is intersection types which require some extra complexity in implementation.

Also note that this is a very common pattern in state-management libraries, that is take a function that returns a partial of the state to be updated. For example [zustand implements this pattern](https://github.com/pmndrs/zustand/blob/3e311520d5c129a0758cf474d030f73ab9754fa1/src/vanilla.ts#L3) and [an user fell for this pitfall shown above](https://github.com/pmndrs/zustand/discussions/1318#discussion-4426244) and their typo compiled. I think we can agree that it'd be annoying if you debugged for a long time just to find a typo that the type-checker didn't catch.

This can be implemented in user-land though...

```ts
type Basket = { bananas: number, apple: number }
declare const updateBasket:
  <F extends [(state: Basket) => ShallowExact<ReturnType<F[0]>, Partial<Basket>>]>(...f: F) => void
  // using variadic args as a hack to workaround the circular constraint

updateBasket(basket => ({ banana: basket.bananas + 1, apple: 10 }))
// Type 'number' is not assignable to type 'never'

type ShallowExact<T, U> =
  T extends U
    ? U extends unknown
        ? { [K in keyof T]: K extends keyof U ? T[K] : never }
        : never
    : U
```