Repository: TypeScript
Issue: [Feature Request] Preserve comments when using Extract<keyof T, string>
Labels: Suggestion,Experience Enhancement

<!-- 🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨

Half of all issues filed here are duplicates, answered in the FAQ, or not appropriate for the bug tracker. Please read the FAQ first, especially the "Common Feature Requests" section.

-->

## Search Terms

mapped type, preserve comment, keyof, Extract

<!-- List of keywords you searched for before creating this issue. Write them down here so that others can find this suggestion more easily -->

## Suggestion

<!-- A summary of what you'd like to see added or changed -->

```ts
type Mapped<T> = {
  [k in keyof T]: ["some transformation", T[k]]
};

interface IFoo {
  /** The string */
  x: string;
  /** The number */
  y: number;
}
declare const mappedIFoo: Mapped<IFoo>;
//Tooltip shows "The string" as the comment
mappedIFoo.x

//////////////////////////
type Mapped2<T> = {
  [k in Extract<keyof T, string>]: ["some transformation", T[k]]
};

declare const mapped2IFoo: Mapped2<IFoo>;
//Tooltip DOES NOT show "The string" as the comment
mapped2IFoo.x
```

[Playground](http://www.typescriptlang.org/play/#src=type%20Mapped%3CT%3E%20%3D%20%7B%0D%0A%20%20%5Bk%20in%20keyof%20T%5D%3A%20%5B%22some%20transformation%22%2C%20T%5Bk%5D%5D%0D%0A%7D%3B%0D%0A%0D%0Ainterface%20IFoo%20%7B%0D%0A%20%20%2F**%20The%20string%20*%2F%0D%0A%20%20x%3A%20string%3B%0D%0A%20%20%2F**%20The%20number%20*%2F%0D%0A%20%20y%3A%20number%3B%0D%0A%7D%0D%0Adeclare%20const%20mappedIFoo%3A%20Mapped%3CIFoo%3E%3B%0D%0A%2F%2FTooltip%20shows%20%22The%20string%22%20as%20the%20comment%0D%0AmappedIFoo.x%0D%0A%0D%0A%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%0D%0Atype%20Mapped2%3CT%3E%20%3D%20%7B%0D%0A%20%20%5Bk%20in%20Extract%3Ckeyof%20T%2C%20string%3E%5D%3A%20%5B%22some%20transformation%22%2C%20T%5Bk%5D%5D%0D%0A%7D%3B%0D%0A%0D%0Adeclare%20const%20mapped2IFoo%3A%20Mapped2%3CIFoo%3E%3B%0D%0A%2F%2FTooltip%20DOES%20NOT%20show%20%22The%20string%22%20as%20the%20comment%0D%0Amapped2IFoo.x)

I'd like it if the fields of the mapped type could somehow preserve the comments of the fields of `T`, even after using `Extract<keyof T, string>`.

## Use Cases

<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->

In my projects, there are many cases where I only want to deal with string keys and not `symbol|number` keys. So, I use `Extract<keyof T, string>` a lot. However, this does not preserve comments and makes me sad =(

## Examples

<!-- Show how this would be used and what the behavior would be -->

```ts
//--noImplicitAny
type Mapped<T extends { [k: string]: any }> = {
  [k in keyof T]: ["some transformation", T[k]]
};
const someSymbol: unique symbol = Symbol();

interface IFoo {
  /** The string */
  x: string;
  /** The number */
  y: number;
  1: "i am a number";
  [someSymbol] : "i am a symbol"
}
declare const mappedIFoo: Mapped<IFoo>;
//Tooltip shows "The string" as the comment
mappedIFoo.x;
//Is allowed, because we use `keyof T`
mappedIFoo[1];
//Is allowed, because we use `keyof T`
mappedIFoo[someSymbol];

//////////////////////////
type Mapped2<T extends { [k : string] : any }> = {
  [k in Extract<keyof T, string>]: ["some transformation", T[k]]
};

declare const mapped2IFoo: Mapped2<IFoo>;
//Expected: Tooltip shows "The string" as the comment
//Actual:   Tooltip DOES NOT show "The string" as the comment
mapped2IFoo.x;
//Expected: is not allowed
//Actual  : Is not allowed; OK!
mapped2IFoo[1];
//Expected: is not allowed
//Actual  : Is not allowed; OK!
mapped2IFoo[someSymbol];
```
[Playground](http://www.typescriptlang.org/play/#src=%2F%2F--noImplicitAny%0D%0Atype%20Mapped%3CT%20extends%20%7B%20%5Bk%3A%20string%5D%3A%20any%20%7D%3E%20%3D%20%7B%0D%0A%20%20%5Bk%20in%20keyof%20T%5D%3A%20%5B%22some%20transformation%22%2C%20T%5Bk%5D%5D%0D%0A%7D%3B%0D%0Aconst%20someSymbol%3A%20unique%20symbol%20%3D%20Symbol()%3B%0D%0A%0D%0Ainterface%20IFoo%20%7B%0D%0A%20%20%2F**%20The%20string%20*%2F%0D%0A%20%20x%3A%20string%3B%0D%0A%20%20%2F**%20The%20number%20*%2F%0D%0A%20%20y%3A%20number%3B%0D%0A%20%201%3A%20%22i%20am%20a%20number%22%3B%0D%0A%20%20%5BsomeSymbol%5D%20%3A%20%22i%20am%20a%20symbol%22%0D%0A%7D%0D%0Adeclare%20const%20mappedIFoo%3A%20Mapped%3CIFoo%3E%3B%0D%0A%2F%2FTooltip%20shows%20%22The%20string%22%20as%20the%20comment%0D%0AmappedIFoo.x%3B%0D%0A%2F%2FIs%20allowed%2C%20because%20we%20use%20%60keyof%20T%60%0D%0AmappedIFoo%5B1%5D%3B%0D%0A%2F%2FIs%20allowed%2C%20because%20we%20use%20%60keyof%20T%60%0D%0AmappedIFoo%5BsomeSymbol%5D%3B%0D%0A%0D%0A%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%0D%0Atype%20Mapped2%3CT%20extends%20%7B%20%5Bk%20%3A%20string%5D%20%3A%20any%20%7D%3E%20%3D%20%7B%0D%0A%20%20%5Bk%20in%20Extract%3Ckeyof%20T%2C%20string%3E%5D%3A%20%5B%22some%20transformation%22%2C%20T%5Bk%5D%5D%0D%0A%7D%3B%0D%0A%0D%0Adeclare%20const%20mapped2IFoo%3A%20Mapped2%3CIFoo%3E%3B%0D%0A%2F%2FExpected%3A%20Tooltip%20shows%20%22The%20string%22%20as%20the%20comment%0D%0A%2F%2FActual%3A%20%20%20Tooltip%20DOES%20NOT%20show%20%22The%20string%22%20as%20the%20comment%0D%0Amapped2IFoo.x%3B%0D%0A%2F%2FExpected%3A%20is%20not%20allowed%0D%0A%2F%2FActual%20%20%3A%20Is%20not%20allowed%3B%20OK!%0D%0Amapped2IFoo%5B1%5D%3B%0D%0A%2F%2FExpected%3A%20is%20not%20allowed%0D%0A%2F%2FActual%20%20%3A%20Is%20not%20allowed%3B%20OK!%0D%0Amapped2IFoo%5BsomeSymbol%5D%3B)

## 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, etc.)
* [X] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).