microsoft / microsoft/TypeScript
Multiple keys being remapped to same key causes unstable modifier propagation
- Langage dominant
- Go
- Étoiles
- 111k
- Forks
- 14.3k
- Merge moyen
- 2 j 4 h
- PR mergées (30 j)
- 132
Description
### 🔎 Search Terms
Mapped Types, Key Remapping
### 🕗 Version & Regression Information
- This has been happening since first release of key remapping at 4.1 (tested with v4.1.5 at Playground) until nightly (tested with v6.0.0-dev.20250822 at Playground).
### ⏯ Playground Link
https://www.typescriptlang.org/play/?#code/C4TwDgpgBAShC2BDMBpCIAqB7AkgOwEtgDEAbABUQCdgAeDAPigF4oBvAKCm6gG0UoBPFADW6LADMoGKIgDOUARAAewCHgAmCgAYASNkIkQqUAGIEqc4AF8AdPsPGoAfThXr2qAH4zFq1AAuRQBdILwAV1JSAG4Oa1iOUEhfS2AAeTBiLDwyFlgEZDRMXEJiMkoaWk4eKAB6WqgAPS8uHgAiCSwsWwAjajavIKsqIQBzWJqOrt7EAC82sPD4HuNY6wYEpOhzVLgAR3CLCA08uCRUdGx8IhIKajpqnnqmlsnO7r75xeXV1u4pj79QZQYZjNYbDhAA
### 💻 Code
```ts
type RemapKeyToInitialPart = {
[K in keyof T as K extends `${infer First}.${infer _Rest}` ? First : K]: null;
};
type FirstOptional = RemapKeyToInitialPart<{
// ^?
"foo.bar"?: string;
"foo.baz": number;
}>;
type FirstRequired = RemapKeyToInitialPart<{
// ^?
"foo.baz": number;
"foo.bar"?: string;
}>;
```
### 🙁 Actual behavior
`type FirstOptional` and `type FirstRequired` results in different types:
- `type FirstOptional` has *optional* property `foo`
- `type FirstRequired` has *required* property `foo`
### 🙂 Expected behavior
`type FirstOptional` and `type FirstRequired` results in same type. I would expect it to be same as ~~`type FirstRequired`~~ `type FirstOptional`.
### Additional information about the issue
My motivation was to implement a utility `type Expand` which transforms `{ "foo.bar": number }` to `{ foo: { bar: number } }` ([playground](https://www.typescriptlang.org/play/?exactOptionalPropertyTypes=true#code/C4TwDgpgBAogHmAhgOwCYB4AqA+KBeKAbwCgoyoBtAaSgEtkoBrCEAewDMpMpEBnKAGK0ATr2AAFRMOAB5duirYAugC4oAJQhiZAIwBWEAMbAsAGkEixk6XIXZsxAL7FioSBdESps+YvxQaCDhgCDR+AAMAEkJ6dghhQUcAOmixYXoAc0dwqAB+QSg1GgAyKDTMlzdoTW19IxNMc0Dg0NR+cuQM3AJuIJCwokpxOgYqJVy1WPioADUoRzzZwtgEFAwSciGRphYOLh5+Yb7WiOiqZOiphJrgbMWb5eQIADd41S4KcSUAbicHYlQRgANlJoIZWMgxFBgABGNTwJBodAbcgAIgAFqwMhAkuwAK4ZRBJMC0NioiZQZB4gC2Oniv02GKxOPYrFYSR0UlRag6GV+jmwv1hSUx2NyuIJiHFJLYZUQwFovHYtC0lJpdISAB8oHi0BBlU9UK4YSLmbi2RypHKFUqVe1gOlOr8AcDQVBwZDgNCAEzw1ZIlFkJnY83sznCbllB2ZBlo0UsyXE0msclqKm0+l-IXe01iiWE6XJ62K5Wq9MaqDa3WAg0QI3AHPx0OWhK8eUlu1Rx184hAA))
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Reproduisez les deux exemples de types mappés à l’aide du TypeScript Playground lié et comparez FirstOptional avec FirstRequired. Étudiez le comportement du compilateur lors du remappage des clés, puis ajoutez un test de régression montrant que les deux ordres de déclaration produisent la même optionalité des propriétés ; la tâche sera considérée comme terminée lorsque le test réussira avec des résultats identiques.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- typescript
- Domaine
- compilers
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 42/100