diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 83f2fa179e4..70827becffe 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3302,7 +3302,7 @@ namespace ts { function writeTypeReference(type: TypeReference, flags: TypeFormatFlags) { const typeArguments = type.typeArguments || emptyArray; if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) { - writeType(typeArguments[0], TypeFormatFlags.InElementType); + writeType(typeArguments[0], TypeFormatFlags.InElementType | TypeFormatFlags.InArrayType); writePunctuation(writer, SyntaxKind.OpenBracketToken); writePunctuation(writer, SyntaxKind.CloseBracketToken); } @@ -3427,9 +3427,15 @@ namespace ts { } function writeTypeOfSymbol(type: ObjectType, typeFormatFlags?: TypeFormatFlags) { + if (typeFormatFlags & TypeFormatFlags.InArrayType) { + writePunctuation(writer, SyntaxKind.OpenParenToken); + } writeKeyword(writer, SyntaxKind.TypeOfKeyword); writeSpace(writer); buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags); + if (typeFormatFlags & TypeFormatFlags.InArrayType) { + writePunctuation(writer, SyntaxKind.CloseParenToken); + } } function writePropertyWithModifiers(prop: Symbol) { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index e58f30a215f..d6d21254218 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -664,7 +664,7 @@ namespace ts { export function createArrayTypeNode(elementType: TypeNode) { const node = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode; - node.elementType = parenthesizeElementTypeMember(elementType); + node.elementType = parenthesizeArrayTypeMember(elementType); return node; } @@ -3898,6 +3898,15 @@ namespace ts { return member; } + export function parenthesizeArrayTypeMember(member: TypeNode) { + switch (member.kind) { + case SyntaxKind.TypeQuery: + case SyntaxKind.TypeOperator: + return createParenthesizedType(member); + } + return parenthesizeElementTypeMember(member); + } + export function parenthesizeElementTypeMembers(members: ReadonlyArray) { return createNodeArray(sameMap(members, parenthesizeElementTypeMember)); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f1f79e57d94..e16ee34b01a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2685,6 +2685,7 @@ namespace ts { SuppressAnyReturnType = 1 << 12, // If the return type is any-like, don't offer a return type. AddUndefined = 1 << 13, // Add undefined to types of initialized, non-optional parameters WriteClassExpressionAsTypeLiteral = 1 << 14, // Write a type literal instead of (Anonymous class) + InArrayType = 1 << 15, // Writing an array element type } export const enum SymbolFormatFlags { diff --git a/tests/baselines/reference/aliasUsageInArray.types b/tests/baselines/reference/aliasUsageInArray.types index 218df8e10ed..ca8f0e61f2f 100644 --- a/tests/baselines/reference/aliasUsageInArray.types +++ b/tests/baselines/reference/aliasUsageInArray.types @@ -18,13 +18,13 @@ interface IHasVisualizationModel { var xs: IHasVisualizationModel[] = [moduleA]; >xs : IHasVisualizationModel[] >IHasVisualizationModel : IHasVisualizationModel ->[moduleA] : typeof moduleA[] +>[moduleA] : (typeof moduleA)[] >moduleA : typeof moduleA var xs2: typeof moduleA[] = [moduleA]; ->xs2 : typeof moduleA[] +>xs2 : (typeof moduleA)[] >moduleA : typeof moduleA ->[moduleA] : typeof moduleA[] +>[moduleA] : (typeof moduleA)[] >moduleA : typeof moduleA === tests/cases/compiler/aliasUsageInArray_backbone.ts === diff --git a/tests/baselines/reference/arrayOfFunctionTypes3.types b/tests/baselines/reference/arrayOfFunctionTypes3.types index 124542f5814..c7251ea45d2 100644 --- a/tests/baselines/reference/arrayOfFunctionTypes3.types +++ b/tests/baselines/reference/arrayOfFunctionTypes3.types @@ -22,8 +22,8 @@ class C { >foo : string } var y = [C, C]; ->y : typeof C[] ->[C, C] : typeof C[] +>y : (typeof C)[] +>[C, C] : (typeof C)[] >C : typeof C >C : typeof C @@ -31,7 +31,7 @@ var r3 = new y[0](); >r3 : C >new y[0]() : C >y[0] : typeof C ->y : typeof C[] +>y : (typeof C)[] >0 : 0 var a: { (x: number): number; (x: string): string; }; diff --git a/tests/baselines/reference/declarationEmitIndexTypeArray.types b/tests/baselines/reference/declarationEmitIndexTypeArray.types index 67f8905639e..549c1efe5f3 100644 --- a/tests/baselines/reference/declarationEmitIndexTypeArray.types +++ b/tests/baselines/reference/declarationEmitIndexTypeArray.types @@ -1,16 +1,16 @@ === tests/cases/compiler/declarationEmitIndexTypeArray.ts === function doSomethingWithKeys(...keys: (keyof T)[]) { } ->doSomethingWithKeys : (...keys: keyof T[]) => void +>doSomethingWithKeys : (...keys: (keyof T)[]) => void >T : T ->keys : keyof T[] +>keys : (keyof T)[] >T : T const utilityFunctions = { ->utilityFunctions : { doSomethingWithKeys: (...keys: keyof T[]) => void; } ->{ doSomethingWithKeys} : { doSomethingWithKeys: (...keys: keyof T[]) => void; } +>utilityFunctions : { doSomethingWithKeys: (...keys: (keyof T)[]) => void; } +>{ doSomethingWithKeys} : { doSomethingWithKeys: (...keys: (keyof T)[]) => void; } doSomethingWithKeys ->doSomethingWithKeys : (...keys: keyof T[]) => void +>doSomethingWithKeys : (...keys: (keyof T)[]) => void }; diff --git a/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt b/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt index c19a13209c9..b578d002e05 100644 --- a/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt +++ b/tests/baselines/reference/keyofIsLiteralContexualType.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/keyofIsLiteralContexualType.ts(5,9): error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type 'keyof T[]'. +tests/cases/compiler/keyofIsLiteralContexualType.ts(5,9): error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type '(keyof T)[]'. Type '"a" | "b" | "c"' is not assignable to type 'keyof T'. Type '"c"' is not assignable to type 'keyof T'. Type '"c"' is not assignable to type '"a" | "b"'. @@ -12,7 +12,7 @@ tests/cases/compiler/keyofIsLiteralContexualType.ts(13,11): error TS2339: Proper let a: (keyof T)[] = ["a", "b"]; let b: (keyof T)[] = ["a", "b", "c"]; ~ -!!! error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type 'keyof T[]'. +!!! error TS2322: Type '("a" | "b" | "c")[]' is not assignable to type '(keyof T)[]'. !!! error TS2322: Type '"a" | "b" | "c"' is not assignable to type 'keyof T'. !!! error TS2322: Type '"c"' is not assignable to type 'keyof T'. !!! error TS2322: Type '"c"' is not assignable to type '"a" | "b"'. diff --git a/tests/cases/fourslash/typeOperatorNodeBuilding.ts b/tests/cases/fourslash/typeOperatorNodeBuilding.ts new file mode 100644 index 00000000000..dea274c03b0 --- /dev/null +++ b/tests/cases/fourslash/typeOperatorNodeBuilding.ts @@ -0,0 +1,21 @@ +/// + +// @Filename: keyof.ts +//// function doSomethingWithKeys(...keys: (keyof T)[]) { } +//// +//// const /*1*/utilityFunctions = { +//// doSomethingWithKeys +//// }; + +// @Filename: typeof.ts +//// class Foo { static a: number; } +//// function doSomethingWithTypes(...statics: (typeof Foo)[]) {} +//// +//// const /*2*/utilityFunctions = { +//// doSomethingWithTypes +//// }; + +verify.quickInfos({ + 1: "const utilityFunctions: {\n doSomethingWithKeys: (...keys: (keyof T)[]) => void;\n}", + 2: "const utilityFunctions: {\n doSomethingWithTypes: (...statics: (typeof Foo)[]) => void;\n}" +});