Skip to content

Commit c55b9ff

Browse files
author
Andy
authored
Merge pull request #13658 from Microsoft/findallrefs_mappedtypes
Support find-all-references on mapped types.
2 parents ceb5fac + b48a281 commit c55b9ff

File tree

5 files changed

+25
-6
lines changed

5 files changed

+25
-6
lines changed

src/compiler/checker.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4618,12 +4618,14 @@ namespace ts {
46184618
const typeParameter = getTypeParameterFromMappedType(type);
46194619
const constraintType = getConstraintTypeFromMappedType(type);
46204620
const templateType = getTemplateTypeFromMappedType(type);
4621-
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type));
4621+
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
46224622
const templateReadonly = !!type.declaration.readonlyToken;
46234623
const templateOptional = !!type.declaration.questionToken;
46244624
if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) {
46254625
// We have a { [P in keyof T]: X }
4626-
forEachType(getLiteralTypeFromPropertyNames(modifiersType), addMemberForKeyType);
4626+
for (const propertySymbol of getPropertiesOfType(modifiersType)) {
4627+
addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol);
4628+
}
46274629
if (getIndexInfoOfType(modifiersType, IndexKind.String)) {
46284630
addMemberForKeyType(stringType);
46294631
}
@@ -4638,7 +4640,7 @@ namespace ts {
46384640
}
46394641
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
46404642

4641-
function addMemberForKeyType(t: Type) {
4643+
function addMemberForKeyType(t: Type, propertySymbol?: Symbol) {
46424644
// Create a mapper from T to the current iteration type constituent. Then, if the
46434645
// mapped type is itself an instantiated type, combine the iteration mapper with the
46444646
// instantiation mapper.
@@ -4654,6 +4656,9 @@ namespace ts {
46544656
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
46554657
prop.type = propType;
46564658
prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp);
4659+
if (propertySymbol) {
4660+
prop.mappedTypeOrigin = propertySymbol;
4661+
}
46574662
members.set(propName, prop);
46584663
}
46594664
else if (t.flags & TypeFlags.String) {
@@ -20233,6 +20238,10 @@ namespace ts {
2023320238
const links = symbol as SymbolLinks;
2023420239
return [links.leftSpread, links.rightSpread];
2023520240
}
20241+
if ((symbol as SymbolLinks).mappedTypeOrigin) {
20242+
return getRootSymbols((symbol as SymbolLinks).mappedTypeOrigin);
20243+
}
20244+
2023620245
let target: Symbol;
2023720246
let next = symbol;
2023820247
while (next = getSymbolLinks(next).target) {

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,6 +2712,7 @@
27122712
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
27132713
leftSpread?: Symbol; // Left source for synthetic spread property
27142714
rightSpread?: Symbol; // Right source for synthetic spread property
2715+
mappedTypeOrigin?: Symbol; // For a property on a mapped type, points back to the orignal 'T' from 'keyof T'.
27152716
hasNonUniformType?: boolean; // True if constituents have non-uniform types
27162717
isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents
27172718
isDiscriminantProperty?: boolean; // True if discriminant synthetic property

tests/baselines/reference/mappedTypes1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ declare let x2: string;
139139
declare let x3: number;
140140
declare let x4: {
141141
toString: void;
142-
valueOf: void;
143142
toFixed: void;
144143
toExponential: void;
145144
toPrecision: void;
145+
valueOf: void;
146146
toLocaleString: void;
147147
};

tests/baselines/reference/mappedTypes1.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ let x3 = f3();
165165
>f3 : <T1 extends number>() => { [P in keyof T1]: void; }
166166

167167
let x4 = f4();
168-
>x4 : { toString: void; valueOf: void; toFixed: void; toExponential: void; toPrecision: void; toLocaleString: void; }
169-
>f4() : { toString: void; valueOf: void; toFixed: void; toExponential: void; toPrecision: void; toLocaleString: void; }
168+
>x4 : { toString: void; toFixed: void; toExponential: void; toPrecision: void; valueOf: void; toLocaleString: void; }
169+
>f4() : { toString: void; toFixed: void; toExponential: void; toPrecision: void; valueOf: void; toLocaleString: void; }
170170
>f4 : <T1 extends Number>() => { [P in keyof T1]: void; }
171171

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface T { [|a|]: number };
4+
////type U { [K in keyof T]: string };
5+
////type V = { [K in keyof U]: boolean };
6+
////const u: U = { [|a|]: "" }
7+
////const v: V = { [|a|]: true }
8+
9+
verify.rangesReferenceEachOther();

0 commit comments

Comments
 (0)