mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-17 21:06:50 -05:00
Better error message for unparenthesized function/constructor type notation in union/intersection types (#39570)
* add graceful error message for unparenthesized function types in union and intersection * add unparenthesizedFunctionTypeInUnionOrIntersection test * add unparenthesizedConstructorTypeInUnionOrIntersection test * Update src/compiler/parser.ts Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> * pass isInUnionType to parseFunctionOrConstructorTypeToError * Apply suggestions from code review Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> * syntax fix * refactor isStartOfFunctionType into isStartOfFunctionTypeOrConstructorType * Update src/compiler/parser.ts Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> * hoist isUnionType Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com> Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
This commit is contained in:
@@ -1164,6 +1164,22 @@
|
||||
"category": "Error",
|
||||
"code": 1384
|
||||
},
|
||||
"Function type notation must be parenthesized when used in a union type.": {
|
||||
"category": "Error",
|
||||
"code": 1385
|
||||
},
|
||||
"Constructor type notation must be parenthesized when used in a union type.": {
|
||||
"category": "Error",
|
||||
"code": 1386
|
||||
},
|
||||
"Function type notation must be parenthesized when used in an intersection type.": {
|
||||
"category": "Error",
|
||||
"code": 1387
|
||||
},
|
||||
"Constructor type notation must be parenthesized when used in an intersection type.": {
|
||||
"category": "Error",
|
||||
"code": 1388
|
||||
},
|
||||
|
||||
"The types of '{0}' are incompatible between these types.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -3569,18 +3569,46 @@ namespace ts {
|
||||
return parsePostfixTypeOrHigher();
|
||||
}
|
||||
|
||||
function parseFunctionOrConstructorTypeToError(
|
||||
isInUnionType: boolean
|
||||
): TypeNode | undefined {
|
||||
// the function type and constructor type shorthand notation
|
||||
// are not allowed directly in unions and intersections, but we'll
|
||||
// try to parse them gracefully and issue a helpful message.
|
||||
if (isStartOfFunctionTypeOrConstructorType()) {
|
||||
const type = parseFunctionOrConstructorType();
|
||||
let diagnostic: DiagnosticMessage;
|
||||
if (isFunctionTypeNode(type)) {
|
||||
diagnostic = isInUnionType
|
||||
? Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_a_union_type
|
||||
: Diagnostics.Function_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;
|
||||
}
|
||||
else {
|
||||
diagnostic = isInUnionType
|
||||
? Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_a_union_type
|
||||
: Diagnostics.Constructor_type_notation_must_be_parenthesized_when_used_in_an_intersection_type;
|
||||
|
||||
}
|
||||
parseErrorAtRange(type, diagnostic);
|
||||
return type;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function parseUnionOrIntersectionType(
|
||||
operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken,
|
||||
parseConstituentType: () => TypeNode,
|
||||
createTypeNode: (types: NodeArray<TypeNode>) => UnionOrIntersectionTypeNode
|
||||
): TypeNode {
|
||||
const pos = getNodePos();
|
||||
const isUnionType = operator === SyntaxKind.BarToken;
|
||||
const hasLeadingOperator = parseOptional(operator);
|
||||
let type = parseConstituentType();
|
||||
let type = hasLeadingOperator && parseFunctionOrConstructorTypeToError(isUnionType)
|
||||
|| parseConstituentType();
|
||||
if (token() === operator || hasLeadingOperator) {
|
||||
const types = [type];
|
||||
while (parseOptional(operator)) {
|
||||
types.push(parseConstituentType());
|
||||
types.push(parseFunctionOrConstructorTypeToError(isUnionType) || parseConstituentType());
|
||||
}
|
||||
type = finishNode(createTypeNode(createNodeArray(types, pos)), pos);
|
||||
}
|
||||
@@ -3595,11 +3623,14 @@ namespace ts {
|
||||
return parseUnionOrIntersectionType(SyntaxKind.BarToken, parseIntersectionTypeOrHigher, factory.createUnionTypeNode);
|
||||
}
|
||||
|
||||
function isStartOfFunctionType(): boolean {
|
||||
function isStartOfFunctionTypeOrConstructorType(): boolean {
|
||||
if (token() === SyntaxKind.LessThanToken) {
|
||||
return true;
|
||||
}
|
||||
return token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType);
|
||||
if (token() === SyntaxKind.OpenParenToken && lookAhead(isUnambiguouslyStartOfFunctionType)) {
|
||||
return true;
|
||||
}
|
||||
return token() === SyntaxKind.NewKeyword;
|
||||
}
|
||||
|
||||
function skipParameterStart(): boolean {
|
||||
@@ -3684,7 +3715,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTypeWorker(noConditionalTypes?: boolean): TypeNode {
|
||||
if (isStartOfFunctionType() || token() === SyntaxKind.NewKeyword) {
|
||||
if (isStartOfFunctionTypeOrConstructorType()) {
|
||||
return parseFunctionOrConstructorType();
|
||||
}
|
||||
const pos = getNodePos();
|
||||
|
||||
Reference in New Issue
Block a user