Repository: TypeScript
Issue: [Feature Request] Allow Class Index Signatures to be mapped
Labels: Suggestion,Awaiting More Feedback

# Suggestion

## 🔍 Search Terms

List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily and help provide feedback.

"mapped class members", "mapped class index signature"

## ✅ 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

We can define index signatures for classes, ie https://www.typescriptlang.org/docs/handbook/2/classes.html#index-signatures, however, these signatures can not be mapped from an existing type, as can be done for object type aliases. It would be useful if similar behavior existed for classes to allow members of a class to be defined based on an existing type.

## 📃 Motivating Example

I am working on typing some existing JS code (can't be changed) that has classes that take in a config in the constructor and then spreads the config into the instance, which means I need to define a type for the config, then define each property of the config as a declare member on the class to get the typing to work, eg:
```ts
type Config = {
    func1?: () => void,
    string1?: string
}

class Foo {
    declare func1?: () => void;
    declare string1?: string;

    constructor(config: Config) {
        Object.assign(this, config)
    }
}
```

However, this is quite tedious and if the configs are significant or have external dependencies then it can be easy to have the Config type out of sync with the manually declared members.

I have made some code examples of what I think would be good [here](https://www.typescriptlang.org/play?ts=4.7.2#code/C4TwDgpgBAwg9gOwGYEsDmUC8UDeBYAKCmKiQFcEBjARgH4AuKACgEosA+KANzhQBMANIRJQAzsABOKBGjqNxUmUKIkEZALYAjCBLlQ1WnYQC+hQpUTioEAB4BDdWAA2EeMnSM3qDNnwri5FTUjKwcuKYEEYQA9NFQAO5wEgDWoqRJUHCaAFYQlMCihKCQUABicHAAQnYSWLjCJADayRAgUNJQLSBwSLCI3gC6nv3oza0DJmYEsVB8cBBpCHDACUnJ6bWUTnaiogvm27tlFfX+UGNtHV09fe5oQ7feFwNQMzoSSVMiFggKZPlJJg-bzDO5sPwiEQAeRyeWAADodqJ0AgmMAABYoUQCKDA9AsBrEKJndQQDFwPjUUI4CLGKBTGaiMhgMBwPZ8KB2JzAHQIOzAFBcCA40TouBkJwc9F2IW4kYYUmGCRpTRkFbqJLQNAQBA6LlQYr7AhbJFQaq1CFNLqMa69LzoB72tAXG5OiYEQly36Sf7AQF4tCg7zgz3Q2H5RG7FFozHYr3Bz3EkSk8mU6m0hlxPZgGr86BYpkLHFLdoIHlOJxYnV7Dalvi2MQo-lkCQLTkIDkAIjmbaWK1sWOAnesEg+tVFcHiCFrZFEdm1hF18TNNSYtgczlc8pY8MCNFCQA)

ie the following should work in terms of showing intellisense for and allowing usage of the mapped members from Config with correct types on class instances:
```ts
type Config = {
    func1?: () => void,
    string1?: string
}

class Foo {
    [key in keyof Config]: Config[key]

    constructor(config: Config) {
        Object.assign(this, config)
    }

    method1() {}
} 

new Foo().func1.?() // should work
```

## Related to
- https://github.com/microsoft/TypeScript/issues/21326
- https://github.com/microsoft/TypeScript/issues/48125