From 0d21c241b2954a1ba8b23f98c6a3f083de22d3bd Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 09:06:46 -0800 Subject: [PATCH 1/2] Support find-all-references on mapped types. * Need to put a 'mappedTypeOrigin' property in SymbolLinks --- src/compiler/checker.ts | 15 ++++++++++++--- src/compiler/types.ts | 1 + tests/cases/fourslash/findAllRefsForMappedType.ts | 9 +++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsForMappedType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bd8ff7568f3..878e7d47273 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4618,12 +4618,14 @@ namespace ts { const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); const templateType = getTemplateTypeFromMappedType(type); - const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); + const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' const templateReadonly = !!type.declaration.readonlyToken; const templateOptional = !!type.declaration.questionToken; if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) { // We have a { [P in keyof T]: X } - forEachType(getLiteralTypeFromPropertyNames(modifiersType), addMemberForKeyType); + for (const propertySymbol of getPropertiesOfType(modifiersType)) { + addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol); + } if (getIndexInfoOfType(modifiersType, IndexKind.String)) { addMemberForKeyType(stringType); } @@ -4638,7 +4640,7 @@ namespace ts { } setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); - function addMemberForKeyType(t: Type) { + function addMemberForKeyType(t: Type, propertySymbol?: Symbol) { // Create a mapper from T to the current iteration type constituent. Then, if the // mapped type is itself an instantiated type, combine the iteration mapper with the // instantiation mapper. @@ -4654,6 +4656,9 @@ namespace ts { const prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName); prop.type = propType; prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp); + if (propertySymbol) { + prop.mappedTypeOrigin = propertySymbol; + } members.set(propName, prop); } else if (t.flags & TypeFlags.String) { @@ -20230,6 +20235,10 @@ namespace ts { const links = symbol as SymbolLinks; return [links.leftSpread, links.rightSpread]; } + if ((symbol as SymbolLinks).mappedTypeOrigin) { + return getRootSymbols((symbol as SymbolLinks).mappedTypeOrigin); + } + let target: Symbol; let next = symbol; while (next = getSymbolLinks(next).target) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6ac7d573eda..8b49af402cf 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2712,6 +2712,7 @@ containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property leftSpread?: Symbol; // Left source for synthetic spread property rightSpread?: Symbol; // Right source for synthetic spread property + mappedTypeOrigin?: Symbol; // For a property on a mapped type, points back to the orignal 'T' from 'keyof T'. hasNonUniformType?: boolean; // True if constituents have non-uniform types isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents isDiscriminantProperty?: boolean; // True if discriminant synthetic property diff --git a/tests/cases/fourslash/findAllRefsForMappedType.ts b/tests/cases/fourslash/findAllRefsForMappedType.ts new file mode 100644 index 00000000000..620eae0815c --- /dev/null +++ b/tests/cases/fourslash/findAllRefsForMappedType.ts @@ -0,0 +1,9 @@ +/// + +////interface T { [|a|]: number }; +////type U { [K in keyof T]: string }; +////type V = { [K in keyof U]: boolean }; +////const u: U = { [|a|]: "" } +////const v: V = { [|a|]: true } + +verify.rangesReferenceEachOther(); From b48a2811f67b66a14cd4584999a7d7ab2e723b56 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Tue, 24 Jan 2017 13:03:16 -0800 Subject: [PATCH 2/2] Update baselines --- tests/baselines/reference/mappedTypes1.js | 2 +- tests/baselines/reference/mappedTypes1.types | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/baselines/reference/mappedTypes1.js b/tests/baselines/reference/mappedTypes1.js index 1998ad5ab6b..4dd8f172179 100644 --- a/tests/baselines/reference/mappedTypes1.js +++ b/tests/baselines/reference/mappedTypes1.js @@ -139,9 +139,9 @@ declare let x2: string; declare let x3: number; declare let x4: { toString: void; - valueOf: void; toFixed: void; toExponential: void; toPrecision: void; + valueOf: void; toLocaleString: void; }; diff --git a/tests/baselines/reference/mappedTypes1.types b/tests/baselines/reference/mappedTypes1.types index 35d13143bab..a9a7f53a899 100644 --- a/tests/baselines/reference/mappedTypes1.types +++ b/tests/baselines/reference/mappedTypes1.types @@ -165,7 +165,7 @@ let x3 = f3(); >f3 : () => { [P in keyof T1]: void; } let x4 = f4(); ->x4 : { toString: void; valueOf: void; toFixed: void; toExponential: void; toPrecision: void; toLocaleString: void; } ->f4() : { toString: void; valueOf: void; toFixed: void; toExponential: void; toPrecision: void; toLocaleString: void; } +>x4 : { toString: void; toFixed: void; toExponential: void; toPrecision: void; valueOf: void; toLocaleString: void; } +>f4() : { toString: void; toFixed: void; toExponential: void; toPrecision: void; valueOf: void; toLocaleString: void; } >f4 : () => { [P in keyof T1]: void; }