Description
TypeScript Version: 3.6.2, and typescript@3.7.0-dev.20190906
Search Terms:
isParameterPropertyDeclaration
Code
Briefly, if a transformer touches the parameters of a constructor via e.g. ts.updateParameter
, then the new node loses its parent
pointer, which produces the following backtrace once TS runs after the transformer. (The below is 3.6.2 to make the line numbers easier for you to match up, but it also repros on the head version.)
TypeError: Cannot read property 'kind' of undefined
at isParameterPropertyDeclaration (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:13411:88)
at Object.filter (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:469:31)
at transformClassMembers (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70629:20)
at createClassDeclarationHeadWithDecorators (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70591:27)
at visitClassDeclaration (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70399:19)
at visitTypeScript (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70247:28)
at visitorWorker (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70041:24)
at sourceElementVisitorWorker (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70066:28)
at saveStateAndInvoke (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:69979:27)
at sourceElementVisitor (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70051:20)
Here's an example transformer that provokes this crash. Note that it doesn't actually change anything in the AST, it just runs ts.updateParameter
with a copy of the input array (using the ...
spread) to force ts.updateParameter
to not early exit.
function transformer(context: ts.TransformationContext): ts.Transformer<ts.SourceFile> {
return (sf: ts.SourceFile) => {
return ts.visitEachChild(sf, visit, context);
};
function visit(node: ts.Node): ts.VisitResult<ts.Node> {
console.log(ts.SyntaxKind[node.kind]);
switch (node.kind) {
case ts.SyntaxKind.Constructor:
const ctor = node as ts.ConstructorDeclaration;
const params = ctor.parameters.map(param => ts.updateParameter(
param,
[...param.decorators!], param.modifiers,
param.dotDotDotToken, param.name, param.questionToken,
param.type, param.initializer));
return ts.updateConstructor(ctor, ctor.decorators, ctor.modifiers,
params, ctor.body);
default:
return ts.visitEachChild(node, visit, context);
}
}
}
Expected behavior:
This code succeeds under TS3.5.
Actual behavior:
This crashes in 3.6.
Playground Link:
Related Issues: