From 52af128d4cd629eb2fcd093682140a972943b9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Wed, 15 Mar 2023 18:06:22 +0000 Subject: [PATCH] Cherry-pick PR #53207 into release-5.0 Component commits: dab0d38b0d Fixed symbol declarations for generic filtering mapped types 681f8bca67 reuse the added mappedType variable in one more place --- src/compiler/checker.ts | 17 ++++++++----- ...ToDefinition_filteringGenericMappedType.ts | 25 +++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/goToDefinition_filteringGenericMappedType.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5e374efbfba36..509bdcea4fd6c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13179,9 +13179,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // and T as the template type. const typeParameter = getTypeParameterFromMappedType(type); const constraintType = getConstraintTypeFromMappedType(type); - const nameType = getNameTypeFromMappedType(type.target as MappedType || type); - const isFilteringMappedType = nameType && isTypeAssignableTo(nameType, typeParameter); - const templateType = getTemplateTypeFromMappedType(type.target as MappedType || type); + const mappedType = (type.target as MappedType) || type; + const nameType = getNameTypeFromMappedType(mappedType); + const shouldLinkPropDeclarations = !nameType || isFilteringMappedType(mappedType); + const templateType = getTemplateTypeFromMappedType(mappedType); const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T' const templateModifiers = getMappedTypeModifiers(type); const include = keyofStringsOnly ? TypeFlags.StringLiteral : TypeFlags.StringOrNumberLiteralOrUnique; @@ -13227,7 +13228,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { prop.links.keyType = keyType; if (modifiersProp) { prop.links.syntheticOrigin = modifiersProp; - prop.declarations = !nameType || isFilteringMappedType ? modifiersProp.declarations : undefined; + prop.declarations = shouldLinkPropDeclarations ? modifiersProp.declarations : undefined; } members.set(propName, prop); } @@ -13360,6 +13361,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } + function isFilteringMappedType(type: MappedType): boolean { + const nameType = getNameTypeFromMappedType(type); + return !!nameType && isTypeAssignableTo(nameType, getTypeParameterFromMappedType(type)); + } + function resolveStructuredTypeMembers(type: StructuredType): ResolvedType { if (!(type as ResolvedType).members) { if (type.flags & TypeFlags.Object) { @@ -17478,8 +17484,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // K is generic and N is assignable to P, instantiate E using a mapper that substitutes the index type for P. // For example, for an index access { [P in K]: Box }[X], we construct the type Box. if (isGenericMappedType(objectType)) { - const nameType = getNameTypeFromMappedType(objectType); - if (!nameType || isTypeAssignableTo(nameType, getTypeParameterFromMappedType(objectType))) { + if (!getNameTypeFromMappedType(objectType) || isFilteringMappedType(objectType)) { return type[cache] = mapType(substituteIndexedMappedType(objectType, type.indexType), t => getSimplifiedType(t, writing)); } } diff --git a/tests/cases/fourslash/goToDefinition_filteringGenericMappedType.ts b/tests/cases/fourslash/goToDefinition_filteringGenericMappedType.ts new file mode 100644 index 0000000000000..95a8ec67ced4c --- /dev/null +++ b/tests/cases/fourslash/goToDefinition_filteringGenericMappedType.ts @@ -0,0 +1,25 @@ +/// + +//// const obj = { +//// get /*def*/id() { +//// return 1; +//// }, +//// name: "test", +//// }; +//// +//// type Omit2 = { +//// [K in keyof T as Exclude]: T[K]; +//// }; +//// +//// declare function omit2( +//// obj: O, +//// mask: Mask +//// ): Omit2; +//// +//// const obj2 = omit2(obj, { +//// name: true, +//// }); +//// +//// obj2.[|/*ref*/id|]; + +verify.goToDefinition("ref", "def");