diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 258ebbeb08cd4..081ed5b6e67bb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3458,11 +3458,7 @@ namespace ts { return symbolToTypeNode(typeAlias, context, SymbolFlags.Type); } else { - context.approximateLength += 3; - if (!(context.flags & NodeBuilderFlags.NoTruncation)) { - return createTypeReferenceNode(createIdentifier("..."), /*typeArguments*/ undefined); - } - return createKeywordTypeNode(SyntaxKind.AnyKeyword); + return createElidedInformationPlaceholder(context); } } else { @@ -3477,11 +3473,7 @@ namespace ts { const depth = context.symbolDepth.get(id) || 0; if (depth > 10) { - context.approximateLength += 3; - if (!(context.flags & NodeBuilderFlags.NoTruncation)) { - return createTypeReferenceNode(createIdentifier("..."), /*typeArguments*/ undefined); - } - return createKeywordTypeNode(SyntaxKind.AnyKeyword); + return createElidedInformationPlaceholder(context); } context.symbolDepth.set(id, depth + 1); context.visitedTypes.set(typeId, true); @@ -3674,10 +3666,15 @@ namespace ts { typeElements.push(signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature, context)); } if (resolvedType.stringIndexInfo) { - const indexInfo = resolvedType.objectFlags & ObjectFlags.ReverseMapped ? - createIndexInfo(anyType, resolvedType.stringIndexInfo.isReadonly, resolvedType.stringIndexInfo.declaration) : - resolvedType.stringIndexInfo; - typeElements.push(indexInfoToIndexSignatureDeclarationHelper(indexInfo, IndexKind.String, context)); + let indexSignature: IndexSignatureDeclaration; + if (resolvedType.objectFlags & ObjectFlags.ReverseMapped) { + indexSignature = indexInfoToIndexSignatureDeclarationHelper(createIndexInfo(anyType, resolvedType.stringIndexInfo.isReadonly, resolvedType.stringIndexInfo.declaration), IndexKind.String, context); + indexSignature.type = createElidedInformationPlaceholder(context); + } + else { + indexSignature = indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String, context); + } + typeElements.push(indexSignature); } if (resolvedType.numberIndexInfo) { typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number, context)); @@ -3711,8 +3708,17 @@ namespace ts { } } + function createElidedInformationPlaceholder(context: NodeBuilderContext) { + context.approximateLength += 3; + if (!(context.flags & NodeBuilderFlags.NoTruncation)) { + return createTypeReferenceNode(createIdentifier("..."), /*typeArguments*/ undefined); + } + return createKeywordTypeNode(SyntaxKind.AnyKeyword); + } + function addPropertyToElementList(propertySymbol: Symbol, context: NodeBuilderContext, typeElements: TypeElement[]) { - const propertyType = getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ? + const propertyIsReverseMapped = !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped); + const propertyType = propertyIsReverseMapped && context.flags & NodeBuilderFlags.InReverseMappedType ? anyType : getTypeOfSymbol(propertySymbol); const saveEnclosingDeclaration = context.enclosingDeclaration; context.enclosingDeclaration = undefined; @@ -3741,8 +3747,14 @@ namespace ts { } else { const savedFlags = context.flags; - context.flags |= !!(getCheckFlags(propertySymbol) & CheckFlags.ReverseMapped) ? NodeBuilderFlags.InReverseMappedType : 0; - const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); + context.flags |= propertyIsReverseMapped ? NodeBuilderFlags.InReverseMappedType : 0; + let propertyTypeNode: TypeNode; + if (propertyIsReverseMapped && !!(savedFlags & NodeBuilderFlags.InReverseMappedType)) { + propertyTypeNode = createElidedInformationPlaceholder(context); + } + else { + propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType, context) : createKeywordTypeNode(SyntaxKind.AnyKeyword); + } context.flags = savedFlags; const modifiers = isReadonlySymbol(propertySymbol) ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined; diff --git a/tests/cases/fourslash/quickInfoMappedTypeRecursiveInference.ts b/tests/cases/fourslash/quickInfoMappedTypeRecursiveInference.ts index ced12951813b3..09046433c12fa 100644 --- a/tests/cases/fourslash/quickInfoMappedTypeRecursiveInference.ts +++ b/tests/cases/fourslash/quickInfoMappedTypeRecursiveInference.ts @@ -18,53 +18,53 @@ verify.quickInfoAt('1', `const out: { a: { - a: any; + a: ...; }; }`); verify.quickInfoAt('2', `function foo<{ a: { - a: any; + a: ...; }; }>(deep: Deep<{ a: { - a: any; + a: ...; }; }>): { a: { - a: any; + a: ...; }; }`); verify.quickInfoAt('3', `(property) a: { a: { - a: any; + a: ...; }; }`); verify.quickInfoAt('4', `(property) a: { a: { - a: any; + a: ...; }; }`); verify.quickInfoAt('5', `(property) a: { a: { - a: any; + a: ...; }; }`); verify.quickInfoAt('6', `const oub: { - [x: string]: any; + [x: string]: ...; }`); verify.quickInfoAt('7', `function foo<{ - [x: string]: any; + [x: string]: ...; }>(deep: Deep<{ - [x: string]: any; + [x: string]: ...; }>): { - [x: string]: any; + [x: string]: ...; }`); verify.quickInfoAt('8', `{ - [x: string]: any; + [x: string]: ...; }`); verify.quickInfoAt('9', `{ - [x: string]: any; + [x: string]: ...; }`); verify.quickInfoAt('10', `{ - [x: string]: any; + [x: string]: ...; }`); diff --git a/tests/cases/fourslash/reverseMappedTypeQuickInfo.ts b/tests/cases/fourslash/reverseMappedTypeQuickInfo.ts new file mode 100644 index 0000000000000..c249db25c6969 --- /dev/null +++ b/tests/cases/fourslash/reverseMappedTypeQuickInfo.ts @@ -0,0 +1,36 @@ +/// + +////interface IAction { +//// type: string; +////} +//// +////type Reducer = (state: S, action: IAction) => S +//// +////function combineReducers(reducers: { [K in keyof S]: Reducer }): Reducer { +//// const dummy = {} as S; +//// return () => dummy; +////} +//// +////const test_inner = (test: string, action: IAction) => { +//// return 'dummy'; +////} +////const test = combineReducers({ +//// test_inner +////}); +//// +////const test_outer = combineReducers({ +//// test +////}); +//// +////// '{test: { test_inner: any } }' +////type FinalType/*1*/ = ReturnType; +//// +////var k: FinalType; +////k.test.test_inner/*2*/ + +verify.quickInfoAt("1", `type FinalType = { + test: { + test_inner: ...; + }; +}`); +verify.quickInfoAt("2", `(property) test_inner: string`);