Repository: TypeScript
Issue: Variant accessors for index signatures and mapped types
Labels: Suggestion,Awaiting More Feedback

# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## 🔍 Search Terms


<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

variant accessors index signatures record

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
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

<!-- A summary of what you'd like to see added or changed -->

Support for having [Variant Accessors](https://github.com/microsoft/TypeScript/pull/42425) with index signature.


## 📃 Motivating Example

<!--
  If you were announcing this feature in a blog post, what's a short explanation that shows
  a developer why this feature improves the language?
-->

```ts
// Simple  usage

interface NumberMap { 
  get [k: string](): number;
  set [k: string](val: string | number);
}

const a: NumberMap = {} 

a.test = '1';
a.test === 1;


// more complex

// makes number properties of an object to allow set `string`
type MakeStringAsNumber<T extends Record<string, any>> = {
  get [ K in keyof T]: T[K]
  set [ K in keyof T]: T[K] extends number ? T[K] | string : T[K]
}

declare const a: MakeStringAsNumber<{ a: boolean, b: number, c: string }>
a.b = '42'; // I want to have this avalible

a.c = '112'

// @ts-expect-error 'a' is boolean
a.a = '2'
```

## 💻 Use Cases

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->

The use case for this feature is [vue 3 reactivity](https://v3.vuejs.org/guide/reactivity-fundamentals.html#creating-standalone-reactive-values-as-refs).


In Vue 3 there's `Ref<T>` (simplified as `{ value: T}`) and `Reactive<UnwrappedRef<T>>` (unwraps `{value: T}` to `T`, recursive)

This feature would allow us to generate a type which can accept a `Ref<T> | T` 

Basically:
```ts
const r = ref({ a: 1} )

r.value.a = 1

const a = reactive(r)
a.a // 1
```

On a `reactive`/`ref` object the set in typescript must be `UnwrappedRef<T>` which is not true, because when you assign to a `reactive` it will unwrap the value:

```ts
const r = ref({a:1});
const a = ref({
  r
}) // results in `{ r: { a: 1 } }` 

a.r = r; // typescript error  because `r` is `Ref<T>` instead of `UnwrappedRef<T>`, but it works at runtime.
```