Appropriately parenthesize keyof and typeof queries in array types (#17272)
* Appropriately parenthesize keyof and typeof queries when they are array types * Fix test and then the same bug in the symbol writer
This commit is contained in:
parent
08a57d82cd
commit
8075353356
|
@ -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) {
|
||||
|
|
|
@ -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<TypeNode>) {
|
||||
return createNodeArray(sameMap(members, parenthesizeElementTypeMember));
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 ===
|
||||
|
|
|
@ -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; };
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
=== tests/cases/compiler/declarationEmitIndexTypeArray.ts ===
|
||||
function doSomethingWithKeys<T>(...keys: (keyof T)[]) { }
|
||||
>doSomethingWithKeys : <T>(...keys: keyof T[]) => void
|
||||
>doSomethingWithKeys : <T>(...keys: (keyof T)[]) => void
|
||||
>T : T
|
||||
>keys : keyof T[]
|
||||
>keys : (keyof T)[]
|
||||
>T : T
|
||||
|
||||
const utilityFunctions = {
|
||||
>utilityFunctions : { doSomethingWithKeys: <T>(...keys: keyof T[]) => void; }
|
||||
>{ doSomethingWithKeys} : { doSomethingWithKeys: <T>(...keys: keyof T[]) => void; }
|
||||
>utilityFunctions : { doSomethingWithKeys: <T>(...keys: (keyof T)[]) => void; }
|
||||
>{ doSomethingWithKeys} : { doSomethingWithKeys: <T>(...keys: (keyof T)[]) => void; }
|
||||
|
||||
doSomethingWithKeys
|
||||
>doSomethingWithKeys : <T>(...keys: keyof T[]) => void
|
||||
>doSomethingWithKeys : <T>(...keys: (keyof T)[]) => void
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -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"'.
|
||||
|
|
21
tests/cases/fourslash/typeOperatorNodeBuilding.ts
Normal file
21
tests/cases/fourslash/typeOperatorNodeBuilding.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: keyof.ts
|
||||
//// function doSomethingWithKeys<T>(...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: <T>(...keys: (keyof T)[]) => void;\n}",
|
||||
2: "const utilityFunctions: {\n doSomethingWithTypes: (...statics: (typeof Foo)[]) => void;\n}"
|
||||
});
|
Loading…
Reference in a new issue