diff --git a/lib/ast-node-types.js b/lib/ast-node-types.js index 10adc1c..0dc9034 100644 --- a/lib/ast-node-types.js +++ b/lib/ast-node-types.js @@ -118,6 +118,7 @@ module.exports = { TSModuleDeclaration: "TSModuleDeclaration", TSNamespaceFunctionDeclaration: "TSNamespaceFunctionDeclaration", TSNonNullExpression: "TSNonNullExpression", + TSNullKeyword: "TSNullKeyword", TSNumberKeyword: "TSNumberKeyword", TSParameterProperty: "TSParameterProperty", TSPropertySignature: "TSPropertySignature", diff --git a/lib/convert.js b/lib/convert.js index 1d55359..ec939bb 100644 --- a/lib/convert.js +++ b/lib/convert.js @@ -1574,13 +1574,20 @@ module.exports = function convert(config) { }); break; - case SyntaxKind.NullKeyword: - Object.assign(result, { - type: AST_NODE_TYPES.Literal, - value: null, - raw: "null" - }); + case SyntaxKind.NullKeyword: { + if (nodeUtils.isWithinTypeAnnotation(node)) { + Object.assign(result, { + type: AST_NODE_TYPES.TSNullKeyword + }); + } else { + Object.assign(result, { + type: AST_NODE_TYPES.Literal, + value: null, + raw: "null" + }); + } break; + } case SyntaxKind.EmptyStatement: case SyntaxKind.DebuggerStatement: diff --git a/lib/node-utils.js b/lib/node-utils.js index 60fcd64..f1b61c3 100644 --- a/lib/node-utils.js +++ b/lib/node-utils.js @@ -197,7 +197,8 @@ module.exports = { getTokenType, convertToken, convertTokens, - getNodeContainer + getNodeContainer, + isWithinTypeAnnotation }; /* eslint-enable no-use-before-define */ @@ -472,6 +473,16 @@ function isOptional(node) { ? (node.questionToken.kind === SyntaxKind.QuestionToken) : false; } +/** + * Returns true if the given TSNode is within the context of a "typeAnnotation", + * which effectively means - is it coming from its parent's `type` or `types` property + * @param {TSNode} node TSNode to be checked + * @returns {boolean} is within "typeAnnotation context" + */ +function isWithinTypeAnnotation(node) { + return node.parent.type === node || (node.parent.types && node.parent.types.indexOf(node) > -1); +} + /** * Fixes the exports of the given TSNode * @param {TSNode} node the TSNode diff --git a/tests/fixtures/typescript/basics/null-and-undefined-type-annotations.src.ts b/tests/fixtures/typescript/basics/null-and-undefined-type-annotations.src.ts new file mode 100644 index 0000000..7d6b582 --- /dev/null +++ b/tests/fixtures/typescript/basics/null-and-undefined-type-annotations.src.ts @@ -0,0 +1,2 @@ +let x: null; +let y: undefined; \ No newline at end of file diff --git a/tests/lib/__snapshots__/typescript.js.snap b/tests/lib/__snapshots__/typescript.js.snap index a079b24..efe8d5d 100644 --- a/tests/lib/__snapshots__/typescript.js.snap +++ b/tests/lib/__snapshots__/typescript.js.snap @@ -15659,6 +15659,209 @@ Object { } `; +exports[`typescript fixtures/basics/null-and-undefined-type-annotations.src 1`] = ` +Object { + "body": Array [ + Object { + "declarations": Array [ + Object { + "id": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 4, + "line": 1, + }, + }, + "name": "x", + "range": Array [ + 4, + 5, + ], + "type": "Identifier", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 1, + }, + "start": Object { + "column": 7, + "line": 1, + }, + }, + "range": Array [ + 7, + 11, + ], + "type": "TypeAnnotation", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 1, + }, + "start": Object { + "column": 7, + "line": 1, + }, + }, + "range": Array [ + 7, + 11, + ], + "type": "TSNullKeyword", + }, + }, + }, + "init": null, + "loc": Object { + "end": Object { + "column": 11, + "line": 1, + }, + "start": Object { + "column": 4, + "line": 1, + }, + }, + "range": Array [ + 4, + 11, + ], + "type": "VariableDeclarator", + }, + ], + "kind": "let", + "loc": Object { + "end": Object { + "column": 12, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 12, + ], + "type": "VariableDeclaration", + }, + Object { + "declarations": Array [ + Object { + "id": Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 2, + }, + "start": Object { + "column": 4, + "line": 2, + }, + }, + "name": "y", + "range": Array [ + 17, + 18, + ], + "type": "Identifier", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 2, + }, + "start": Object { + "column": 7, + "line": 2, + }, + }, + "range": Array [ + 20, + 29, + ], + "type": "TypeAnnotation", + "typeAnnotation": Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 2, + }, + "start": Object { + "column": 7, + "line": 2, + }, + }, + "range": Array [ + 20, + 29, + ], + "type": "TSUndefinedKeyword", + }, + }, + }, + "init": null, + "loc": Object { + "end": Object { + "column": 16, + "line": 2, + }, + "start": Object { + "column": 4, + "line": 2, + }, + }, + "range": Array [ + 17, + 29, + ], + "type": "VariableDeclarator", + }, + ], + "kind": "let", + "loc": Object { + "end": Object { + "column": 17, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 2, + }, + }, + "range": Array [ + 13, + 30, + ], + "type": "VariableDeclaration", + }, + ], + "loc": Object { + "end": Object { + "column": 17, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 30, + ], + "sourceType": "script", + "type": "Program", +} +`; + exports[`typescript fixtures/basics/type-alias-declaration.src 1`] = ` Object { "body": Array [