Skip to content

Commit dc4871a

Browse files
committed
Parenthesize the fn or constructor type with type parameter when writing it in type argument
Fixes microsoft#8105
1 parent 87b64c5 commit dc4871a

File tree

5 files changed

+24
-66
lines changed

5 files changed

+24
-66
lines changed

src/compiler/checker.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1990,7 +1990,7 @@ namespace ts {
19901990
}
19911991
if (pos < end) {
19921992
writePunctuation(writer, SyntaxKind.LessThanToken);
1993-
writeType(typeArguments[pos], TypeFormatFlags.None);
1993+
writeType(typeArguments[pos], TypeFormatFlags.InFirstTypeArgument);
19941994
pos++;
19951995
while (pos < end) {
19961996
writePunctuation(writer, SyntaxKind.CommaToken);
@@ -2143,6 +2143,19 @@ namespace ts {
21432143
}
21442144
}
21452145

2146+
function shouldAddParenthesisAroundFunctionType(callSignature: Signature, flags: TypeFormatFlags) {
2147+
if (flags & TypeFormatFlags.InElementType) {
2148+
return true;
2149+
}
2150+
else if (flags & TypeFormatFlags.InFirstTypeArgument) {
2151+
// Add parenthesis around function type for the first type argument to avoid ambiguity
2152+
const typeParameters = callSignature.target && (flags & TypeFormatFlags.WriteTypeArgumentsOfSignature) ?
2153+
callSignature.target.typeParameters : callSignature.typeParameters;
2154+
return typeParameters && typeParameters.length !== 0;
2155+
}
2156+
return false;
2157+
}
2158+
21462159
function writeLiteralType(type: ObjectType, flags: TypeFormatFlags) {
21472160
const resolved = resolveStructuredTypeMembers(type);
21482161
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
@@ -2153,11 +2166,12 @@ namespace ts {
21532166
}
21542167

21552168
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
2156-
if (flags & TypeFormatFlags.InElementType) {
2169+
const parenthesizeSignature = shouldAddParenthesisAroundFunctionType(resolved.callSignatures[0], flags);
2170+
if (parenthesizeSignature) {
21572171
writePunctuation(writer, SyntaxKind.OpenParenToken);
21582172
}
21592173
buildSignatureDisplay(resolved.callSignatures[0], writer, enclosingDeclaration, globalFlagsToPass | TypeFormatFlags.WriteArrowStyleSignature, /*kind*/ undefined, symbolStack);
2160-
if (flags & TypeFormatFlags.InElementType) {
2174+
if (parenthesizeSignature) {
21612175
writePunctuation(writer, SyntaxKind.CloseParenToken);
21622176
}
21632177
return;
@@ -2317,12 +2331,14 @@ namespace ts {
23172331
function buildDisplayForTypeArgumentsAndDelimiters(typeParameters: TypeParameter[], mapper: TypeMapper, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
23182332
if (typeParameters && typeParameters.length) {
23192333
writePunctuation(writer, SyntaxKind.LessThanToken);
2334+
let flags = TypeFormatFlags.InFirstTypeArgument;
23202335
for (let i = 0; i < typeParameters.length; i++) {
23212336
if (i > 0) {
23222337
writePunctuation(writer, SyntaxKind.CommaToken);
23232338
writeSpace(writer);
2339+
flags = TypeFormatFlags.None;
23242340
}
2325-
buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, TypeFormatFlags.None);
2341+
buildTypeDisplay(mapper(typeParameters[i]), writer, enclosingDeclaration, flags);
23262342
}
23272343
writePunctuation(writer, SyntaxKind.GreaterThanToken);
23282344
}

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,6 +1820,7 @@ namespace ts {
18201820
WriteTypeArgumentsOfSignature = 0x00000020, // Write the type arguments instead of type parameters of the signature
18211821
InElementType = 0x00000040, // Writing an array or union element type
18221822
UseFullyQualifiedType = 0x00000080, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
1823+
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
18231824
}
18241825

18251826
export const enum SymbolFormatFlags {

tests/baselines/reference/declarationEmitPromise.js

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -60,63 +60,4 @@ export declare class bluebird<T> {
6060
static all: Array<bluebird<any>>;
6161
}
6262
export declare function runSampleWorks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>;
63-
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>;
64-
65-
66-
//// [DtsFileErrors]
67-
68-
69-
tests/cases/compiler/declarationEmitPromise.d.ts(5,141): error TS2314: Generic type 'Promise<T>' requires 1 type argument(s).
70-
tests/cases/compiler/declarationEmitPromise.d.ts(5,148): error TS1144: '{' or ';' expected.
71-
tests/cases/compiler/declarationEmitPromise.d.ts(5,150): error TS2304: Cannot find name 'T'.
72-
tests/cases/compiler/declarationEmitPromise.d.ts(5,153): error TS2304: Cannot find name 'f'.
73-
tests/cases/compiler/declarationEmitPromise.d.ts(5,154): error TS1005: ')' expected.
74-
tests/cases/compiler/declarationEmitPromise.d.ts(5,160): error TS2304: Cannot find name 'A'.
75-
tests/cases/compiler/declarationEmitPromise.d.ts(5,167): error TS2304: Cannot find name 'B'.
76-
tests/cases/compiler/declarationEmitPromise.d.ts(5,174): error TS2304: Cannot find name 'C'.
77-
tests/cases/compiler/declarationEmitPromise.d.ts(5,181): error TS2304: Cannot find name 'D'.
78-
tests/cases/compiler/declarationEmitPromise.d.ts(5,188): error TS2304: Cannot find name 'E'.
79-
tests/cases/compiler/declarationEmitPromise.d.ts(5,194): error TS2304: Cannot find name 'T'.
80-
tests/cases/compiler/declarationEmitPromise.d.ts(5,195): error TS1005: ';' expected.
81-
tests/cases/compiler/declarationEmitPromise.d.ts(5,197): error TS1128: Declaration or statement expected.
82-
tests/cases/compiler/declarationEmitPromise.d.ts(5,200): error TS2304: Cannot find name 'T'.
83-
tests/cases/compiler/declarationEmitPromise.d.ts(5,202): error TS1109: Expression expected.
84-
85-
86-
==== tests/cases/compiler/declarationEmitPromise.d.ts (15 errors) ====
87-
export declare class bluebird<T> {
88-
static all: Array<bluebird<any>>;
89-
}
90-
export declare function runSampleWorks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T) & {}>;
91-
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>;
92-
~~~~~~~
93-
!!! error TS2314: Generic type 'Promise<T>' requires 1 type argument(s).
94-
~~
95-
!!! error TS1144: '{' or ';' expected.
96-
~
97-
!!! error TS2304: Cannot find name 'T'.
98-
~
99-
!!! error TS2304: Cannot find name 'f'.
100-
~
101-
!!! error TS1005: ')' expected.
102-
~
103-
!!! error TS2304: Cannot find name 'A'.
104-
~
105-
!!! error TS2304: Cannot find name 'B'.
106-
~
107-
!!! error TS2304: Cannot find name 'C'.
108-
~
109-
!!! error TS2304: Cannot find name 'D'.
110-
~
111-
!!! error TS2304: Cannot find name 'E'.
112-
~
113-
!!! error TS2304: Cannot find name 'T'.
114-
~
115-
!!! error TS1005: ';' expected.
116-
~~
117-
!!! error TS1128: Declaration or statement expected.
118-
~
119-
!!! error TS2304: Cannot find name 'T'.
120-
~
121-
!!! error TS1109: Expression expected.
122-
63+
export declare function runSampleBreaks<A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>): Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>;

tests/baselines/reference/declarationEmitPromise.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export async function runSampleWorks<A, B, C, D, E>(
9696
}
9797

9898
export async function runSampleBreaks<A, B, C, D, E>(
99-
>runSampleBreaks : <A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>) => Promise<<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T>
99+
>runSampleBreaks : <A, B, C, D, E>(a: bluebird<A>, b?: bluebird<B>, c?: bluebird<C>, d?: bluebird<D>, e?: bluebird<E>) => Promise<(<T>(f: (a: A, b?: B, c?: C, d?: D, e?: E) => T) => T)>
100100
>A : A
101101
>B : B
102102
>C : C

tests/baselines/reference/specializedLambdaTypeArguments.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class X<A> {
44
>A : A
55

66
prop: X< <Tany>() => Tany >;
7-
>prop : X<<Tany>() => Tany>
7+
>prop : X<(<Tany>() => Tany)>
88
>X : X<A>
99
>Tany : Tany
1010
>Tany : Tany

0 commit comments

Comments
 (0)