diff --git a/src/parser/plugins/types.ts b/src/parser/plugins/types.ts index 935c289a..4778fc31 100644 --- a/src/parser/plugins/types.ts +++ b/src/parser/plugins/types.ts @@ -1,6 +1,6 @@ -import {eat, lookaheadType, match} from "../tokenizer/index"; +import {eatTypeToken, lookaheadType, match} from "../tokenizer/index"; import {TokenType as tt} from "../tokenizer/types"; -import {isFlowEnabled, isTypeScriptEnabled, state} from "../traverser/base"; +import {isFlowEnabled, isTypeScriptEnabled} from "../traverser/base"; import {baseParseConditional} from "../traverser/expression"; import {flowParseTypeAnnotation} from "./flow"; import {tsParseTypeAnnotation} from "./typescript"; @@ -26,9 +26,7 @@ export function typedParseConditional(noIn: boolean): void { // Note: These "type casts" are *not* valid TS expressions. // But we parse them here and change them when completing the arrow function. export function typedParseParenItem(): void { - if (eat(tt.question)) { - state.tokens[state.tokens.length - 1].isType = true; - } + eatTypeToken(tt.question); if (match(tt.colon)) { if (isTypeScriptEnabled) { tsParseTypeAnnotation(); diff --git a/src/parser/tokenizer/index.ts b/src/parser/tokenizer/index.ts index 74efa955..63bdc423 100644 --- a/src/parser/tokenizer/index.ts +++ b/src/parser/tokenizer/index.ts @@ -189,6 +189,13 @@ export function eat(type: TokenType): boolean { } } +export function eatTypeToken(tokenType: TokenType): void { + const oldIsType = state.isType; + state.isType = true; + eat(tokenType); + state.isType = oldIsType; +} + export function match(type: TokenType): boolean { return state.type === type; } diff --git a/src/parser/traverser/statement.ts b/src/parser/traverser/statement.ts index ebe939f0..4b7adacb 100644 --- a/src/parser/traverser/statement.ts +++ b/src/parser/traverser/statement.ts @@ -36,6 +36,7 @@ import { } from "../plugins/typescript"; import { eat, + eatTypeToken, IdentifierRole, lookaheadType, lookaheadTypeAndKeyword, @@ -819,7 +820,7 @@ export function parsePostMemberNameModifiers(): void { export function parseClassProperty(): void { if (isTypeScriptEnabled) { - eat(tt.bang); + eatTypeToken(tt.bang); tsTryParseTypeAnnotation(); } else if (isFlowEnabled) { if (match(tt.colon)) { diff --git a/test/typescript-test.ts b/test/typescript-test.ts index e4d4ccfc..087b2797 100644 --- a/test/typescript-test.ts +++ b/test/typescript-test.ts @@ -1074,6 +1074,22 @@ describe("typescript transform", () => { ); }); + it("handles definite assignment assertions in classes with disableESTransforms", () => { + assertTypeScriptResult( + ` + class A { + foo!: number; + } + `, + `"use strict"; + class A { + foo; + } + `, + {disableESTransforms: true}, + ); + }); + it("handles definite assignment assertions on variables", () => { assertTypeScriptResult( ` @@ -1089,6 +1105,37 @@ describe("typescript transform", () => { ); }); + it("handles definite assignment assertions on private fields in classes", () => { + assertTypeScriptResult( + ` + class A { + #a!: number; + } + `, + `"use strict"; + class A { + #a; + } + `, + ); + }); + + it("handles definite assignment assertions on private fields in classes with disableESTransforms", () => { + assertTypeScriptResult( + ` + class A { + #a!: number; + } + `, + `"use strict"; + class A { + #a; + } + `, + {disableESTransforms: true}, + ); + }); + it("handles mapped type modifiers", () => { assertTypeScriptResult( `