Skip to content

Commit e7dff1b

Browse files
type-level assertion operator (!)... parsing still fails
checker errors with JSDocUnknownType, but didn't parse that?
1 parent 5e8e735 commit e7dff1b

File tree

9 files changed

+94
-1
lines changed

9 files changed

+94
-1
lines changed

src/compiler/checker.ts

+14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
/// <reference path="moduleNameResolver.ts"/>
22
/// <reference path="binder.ts"/>
3+
/// <reference types="node"/>
4+
declare var console: Console;
35

46
/* @internal */
57
namespace ts {
@@ -7540,6 +7542,14 @@ namespace ts {
75407542
return links.resolvedType;
75417543
}
75427544

7545+
function getTypeFromPostfixedTypeOperatorNode(node: NonNullTypeNode) { // TypeOperatorNode
7546+
const links = getNodeLinks(node);
7547+
if (!links.resolvedType) {
7548+
links.resolvedType = getNonNullableType(getTypeFromTypeNode(node.type));
7549+
}
7550+
return links.resolvedType;
7551+
}
7552+
75437553
function createIndexedAccessType(objectType: Type, indexType: Type) {
75447554
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
75457555
type.objectType = objectType;
@@ -7997,6 +8007,8 @@ namespace ts {
79978007
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
79988008
case SyntaxKind.TypeOperator:
79998009
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
8010+
case SyntaxKind.NonNullTypeNode:
8011+
return getTypeFromPostfixedTypeOperatorNode(<NonNullTypeNode>node);
80008012
case SyntaxKind.IndexedAccessType:
80018013
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
80028014
case SyntaxKind.MappedType:
@@ -18701,6 +18713,7 @@ namespace ts {
1870118713
}
1870218714

1870318715
function checkTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments) {
18716+
if (allowSyntheticDefaultImports) console.trace("checkTypeReferenceNode");
1870418717
checkGrammarTypeArguments(node, node.typeArguments);
1870518718
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJavaScriptFile(node) && !isInJSDoc(node)) {
1870618719
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
@@ -22315,6 +22328,7 @@ namespace ts {
2231522328
case SyntaxKind.JSDocAllType:
2231622329
case SyntaxKind.JSDocUnknownType:
2231722330
if (!isInJavaScriptFile(node) && !isInJSDoc(node)) {
22331+
if (allowSyntheticDefaultImports) console.trace("JSDocUnknownType");
2231822332
grammarErrorOnNode(node, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
2231922333
}
2232022334
return;

src/compiler/emitter.ts

+2
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,8 @@ namespace ts {
797797
return emitAsExpression(<AsExpression>node);
798798
case SyntaxKind.NonNullExpression:
799799
return emitNonNullExpression(<NonNullExpression>node);
800+
case SyntaxKind.NonNullTypeNode:
801+
return emitWithSuffix((<NonNullTypeNode>node).type, "!");
800802
case SyntaxKind.MetaProperty:
801803
return emitMetaProperty(<MetaProperty>node);
802804

src/compiler/factory.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,18 @@ namespace ts {
12611261
: node;
12621262
}
12631263

1264+
export function createNonNullTypeNode(type: TypeNode) {
1265+
const node = <NonNullTypeNode>createSynthesizedNode(SyntaxKind.NonNullTypeNode);
1266+
node.type = parenthesizeElementTypeMember(type);
1267+
return node;
1268+
}
1269+
1270+
export function updateNonNullTypeNode(node: NonNullTypeNode, type: TypeNode) {
1271+
return node.type !== type
1272+
? updateNode(createNonNullTypeNode(type), node)
1273+
: node;
1274+
}
1275+
12641276
export function createMetaProperty(keywordToken: MetaProperty["keywordToken"], name: Identifier) {
12651277
const node = <MetaProperty>createSynthesizedNode(SyntaxKind.MetaProperty);
12661278
node.keywordToken = keywordToken;

src/compiler/parser.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ namespace ts {
207207
visitNode(cbNode, (<AsExpression>node).type);
208208
case SyntaxKind.NonNullExpression:
209209
return visitNode(cbNode, (<NonNullExpression>node).expression);
210+
case SyntaxKind.NonNullTypeNode:
211+
return visitNode(cbNode, (<NonNullTypeNode>node).type);
210212
case SyntaxKind.MetaProperty:
211213
return visitNode(cbNode, (<MetaProperty>node).name);
212214
case SyntaxKind.ConditionalExpression:
@@ -1959,6 +1961,7 @@ namespace ts {
19591961
while (parseOptional(SyntaxKind.DotToken)) {
19601962
if (token() === SyntaxKind.LessThanToken) {
19611963
// the entity is part of a JSDoc-style generic, so record the trailing dot for later error reporting
1964+
console.trace("parseEntityName:jsdocDotPos");
19621965
entity.jsdocDotPos = dotPos;
19631966
break;
19641967
}
@@ -2122,6 +2125,7 @@ namespace ts {
21222125
}
21232126

21242127
function parseJSDocUnknownOrNullableType(): JSDocUnknownType | JSDocNullableType {
2128+
console.trace("parseJSDocUnknownOrNullableType");
21252129
const pos = scanner.getStartPos();
21262130
// skip the ?
21272131
nextToken();
@@ -2657,6 +2661,7 @@ namespace ts {
26572661
case SyntaxKind.AsteriskToken:
26582662
return parseJSDocAllType();
26592663
case SyntaxKind.QuestionToken:
2664+
console.trace("parseNonArrayType:QuestionToken");
26602665
return parseJSDocUnknownOrNullableType();
26612666
case SyntaxKind.FunctionKeyword:
26622667
return parseJSDocFunctionType();
@@ -2794,7 +2799,31 @@ namespace ts {
27942799
case SyntaxKind.KeyOfKeyword:
27952800
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
27962801
}
2797-
return parseArrayTypeOrHigher();
2802+
const type = parseArrayTypeOrHigher();
2803+
return parsePostfixTypeOperatorOrHigher(type);
2804+
}
2805+
2806+
function parsePostfixTypeOperator(type: TypeNode) { // , operator: SyntaxKind.NonNullTypeNode
2807+
// const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
2808+
const node = <NonNullTypeNode>createNode(SyntaxKind.NonNullTypeNode);
2809+
// parseExpected(operator);
2810+
parseExpected(SyntaxKind.ExclamationToken);
2811+
// node.operator = operator;
2812+
node.type = type;
2813+
return finishNode(node);
2814+
}
2815+
2816+
function parsePostfixTypeOperatorOrHigher(type: TypeNode): TypeNode {
2817+
let postfixed: TypeNode;
2818+
switch (token()) {
2819+
case SyntaxKind.NonNullTypeNode:
2820+
return parsePostfixTypeOperator(type); // , SyntaxKind.NonNullTypeNode
2821+
}
2822+
if (postfixed) {
2823+
return parsePostfixTypeOperatorOrHigher(postfixed);
2824+
} else {
2825+
return type;
2826+
}
27982827
}
27992828

28002829
function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {

src/compiler/types.ts

+6
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ namespace ts {
272272
ExpressionWithTypeArguments,
273273
AsExpression,
274274
NonNullExpression,
275+
NonNullTypeNode,
275276
MetaProperty,
276277

277278
// Misc
@@ -1545,6 +1546,11 @@ namespace ts {
15451546
expression: Expression;
15461547
}
15471548

1549+
export interface NonNullTypeNode extends TypeNode {
1550+
kind: SyntaxKind.NonNullTypeNode;
1551+
type: TypeNode;
1552+
}
1553+
15481554
// NOTE: MetaProperty is really a MemberExpression, but we consider it a PrimaryExpression
15491555
// for the same reasons we treat NewExpression as a PrimaryExpression.
15501556
export interface MetaProperty extends PrimaryExpression {

src/compiler/visitor.ts

+4
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,10 @@ namespace ts {
562562
return updateNonNullExpression(<NonNullExpression>node,
563563
visitNode((<NonNullExpression>node).expression, visitor, isExpression));
564564

565+
case SyntaxKind.NonNullTypeNode:
566+
return updateNonNullTypeNode(<NonNullTypeNode>node,
567+
visitNode((<NonNullTypeNode>node).type, visitor, isTypeNode));
568+
565569
case SyntaxKind.MetaProperty:
566570
return updateMetaProperty(<MetaProperty>node,
567571
visitNode((<MetaProperty>node).name, visitor, isIdentifier));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
tests/cases/compiler/nonNullType.ts(2,10): error TS8020: JSDoc types can only be used inside documentation comments.
2+
3+
4+
==== tests/cases/compiler/nonNullType.ts (1 errors) ====
5+
type a = string | undefined | null | never;
6+
type b = a!;
7+
~~
8+
!!! error TS8020: JSDoc types can only be used inside documentation comments.
9+
// type Assert<T> = T!;
10+
// type c = Assert<a>;
11+
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//// [nonNullType.ts]
2+
type a = string | undefined | null | never;
3+
type b = a!;
4+
// type Assert<T> = T!;
5+
// type c = Assert<a>;
6+
7+
8+
//// [nonNullType.js]
9+
// type Assert<T> = T!;
10+
// type c = Assert<a>;

tests/cases/compiler/nonNullType.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @allowSyntheticDefaultImports: true
2+
type a = string | undefined | null | never;
3+
type b = a!;
4+
// type Assert<T> = T!;
5+
// type c = Assert<a>;

0 commit comments

Comments
 (0)