Skip to content

Commit f824e72

Browse files
authored
Give mapped type properties a synthetic declaration name (microsoft#18023)
* Escape symbol names which are not valid identifiers and wrap them in quotes * Pass forward type, do work in getNameOfSymbol * Minimal test * Fix nit
1 parent 336df75 commit f824e72

File tree

6 files changed

+54
-1
lines changed

6 files changed

+54
-1
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3114,6 +3114,12 @@ namespace ts {
31143114
return "(Anonymous function)";
31153115
}
31163116
}
3117+
if ((symbol as TransientSymbol).syntheticLiteralTypeOrigin) {
3118+
const stringValue = (symbol as TransientSymbol).syntheticLiteralTypeOrigin.value;
3119+
if (!isIdentifierText(stringValue, compilerOptions.target)) {
3120+
return `"${escapeString(stringValue, CharacterCodes.doubleQuote)}"`;
3121+
}
3122+
}
31173123
return unescapeLeadingUnderscores(symbol.escapedName);
31183124
}
31193125

@@ -5724,7 +5730,14 @@ namespace ts {
57245730
}
57255731
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
57265732

5727-
function addMemberForKeyType(t: Type, propertySymbol?: Symbol) {
5733+
function addMemberForKeyType(t: Type, propertySymbolOrIndex?: Symbol | number) {
5734+
let propertySymbol: Symbol;
5735+
// forEachType delegates to forEach, which calls with a numeric second argument
5736+
// the type system currently doesn't catch this incompatibility, so we annotate
5737+
// the function ourselves to indicate the runtime behavior and deal with it here
5738+
if (typeof propertySymbolOrIndex === "object") {
5739+
propertySymbol = propertySymbolOrIndex;
5740+
}
57285741
// Create a mapper from T to the current iteration type constituent. Then, if the
57295742
// mapped type is itself an instantiated type, combine the iteration mapper with the
57305743
// instantiation mapper.
@@ -5744,6 +5757,7 @@ namespace ts {
57445757
prop.syntheticOrigin = propertySymbol;
57455758
prop.declarations = propertySymbol.declarations;
57465759
}
5760+
prop.syntheticLiteralTypeOrigin = t as StringLiteralType;
57475761
members.set(propName, prop);
57485762
}
57495763
else if (t.flags & TypeFlags.String) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2972,6 +2972,7 @@ namespace ts {
29722972
leftSpread?: Symbol; // Left source for synthetic spread property
29732973
rightSpread?: Symbol; // Right source for synthetic spread property
29742974
syntheticOrigin?: Symbol; // For a property on a mapped or spread type, points back to the original property
2975+
syntheticLiteralTypeOrigin?: StringLiteralType; // For a property on a mapped type, indicates the type whose text to use as the declaration name, instead of the symbol name
29752976
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
29762977
resolvedExports?: SymbolTable; // Resolved exports of module
29772978
exportsChecked?: boolean; // True if exports of external module have been checked
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//// [declarationQuotedMembers.ts]
2+
export declare const mapped: { [K in 'a-b-c']: number }
3+
export const example = mapped;
4+
5+
//// [declarationQuotedMembers.js]
6+
"use strict";
7+
exports.__esModule = true;
8+
exports.example = exports.mapped;
9+
10+
11+
//// [declarationQuotedMembers.d.ts]
12+
export declare const mapped: {
13+
[K in 'a-b-c']: number;
14+
};
15+
export declare const example: {
16+
"a-b-c": number;
17+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/declarationQuotedMembers.ts ===
2+
export declare const mapped: { [K in 'a-b-c']: number }
3+
>mapped : Symbol(mapped, Decl(declarationQuotedMembers.ts, 0, 20))
4+
>K : Symbol(K, Decl(declarationQuotedMembers.ts, 0, 32))
5+
6+
export const example = mapped;
7+
>example : Symbol(example, Decl(declarationQuotedMembers.ts, 1, 12))
8+
>mapped : Symbol(mapped, Decl(declarationQuotedMembers.ts, 0, 20))
9+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/compiler/declarationQuotedMembers.ts ===
2+
export declare const mapped: { [K in 'a-b-c']: number }
3+
>mapped : { a-b-c: number; }
4+
>K : K
5+
6+
export const example = mapped;
7+
>example : { a-b-c: number; }
8+
>mapped : { a-b-c: number; }
9+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// @declaration: true
2+
export declare const mapped: { [K in 'a-b-c']: number }
3+
export const example = mapped;

0 commit comments

Comments
 (0)