You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[TS 4.8] Deprecated factory methods aren't usable with originalNode.modifiers #49939
Deprecated factory methods aren't usable with originalNode.modifiers.
#49089 changed Node.prototype.modifiers from NodeArray<Modifier> to NodeArray<Modifier | Decorator>. It also changed factory functions to accept a single NodeArray<Modifier | Decorator> argument instead of separate modifiers and decorators arguments. The old factory functions are still available (they are deprecated now). But I imagine most usages of those old functions now result in a compile error for passing in originalNode.modifiers:
Argument of type 'NodeArray' is not assignable to parameter of type 'readonly Modifier[]'
Note: Not sure how to reproduce this in the playground. import from "typescript" doesn't seem to import nightly typings in the playground.
💻 Code
import*astsfrom"typescript";functiontransformClassDecl(orig: ts.ClassDeclaration){returnts.factory.updateClassDeclaration(orig,orig.decorators,orig.modifiers,// ^^^^^^^^^^^^^^ TS2345: Argument of type 'NodeArray<ModifierLike>' is not assignable to parameter of type 'readonly Modifier[]'.orig.name,orig.typeParameters,orig.heritageClauses,orig.members);}
🙁 Actual behavior
This code snippet fails to compile with the error message inlined in the snippet.
🙂 Expected behavior
Ideally the deprecated factory.updateXxx functions would still be usable as before. This would make the upgrade to TypeScript 4.8 easier.
I imagine most usages pass in originalNode.modifiers unchanged, unless they modify the modifiers. Picking Angular as a random example:
Unfortunately, there's only so much we can do for backwards compatibility here. If we were to allow ModifierLike[] for the modifiers parameter, we would have to somehow differentiate between decorators supplied via the decorators parameter and existing decorators that may be passed via modifiers. However, there's no way to mitigate that kind of collision.
If you need to support both TS 4.7 and TS 4.8, my recommendation would be to do as you have described in the workaround, or to branch based on ts.version or ts.versionMajorMinor. Note that #50343 will likely further break compatibility here in favor of producing expected build breaks when accessing decorators, though TS 4.8 exports several functions that can help to access only the decorators or modifiers of a node:
ts.canHaveModifiers(node)
ts.canHaveDecorators(node)
ts.getModifiers(node)
ts.getDecorators(node)
To bridge between 4.7 and 4.8, I would recommend you have something like the following in your code:
functiontryGetDecorators(ts: typeofimport("typescript"),node: Node){if(typeofts.getDecorators==="function"){// TS 4.8 and laterreturnts.canHaveDecorators(node) ? ts.getDecorators(node) : undefined;}// TS 4.7 and earlierreturnnode.decorators;}functiontryGetModifiers(ts: typeofimport("typescript"),node: Node){if(typeofts.getModifiers==="function"){// TS 4.8 and laterreturnts.canHaveModifiers(node) ? ts.getModifiers(node) : undefined;}// TS 4.7 and earlier// NOTE: Returns original array if every node was a `Modifier`, since the `update` methods on `NodeFactory`// use reference equality.returnts.visitNodes(node.modifiers,node=>ts.isModifier(node) ? node : undefined,ts.isModifier);}
Activity
rbuckton commentedon Aug 19, 2022
Unfortunately, there's only so much we can do for backwards compatibility here. If we were to allow
ModifierLike[]for themodifiersparameter, we would have to somehow differentiate between decorators supplied via thedecoratorsparameter and existing decorators that may be passed viamodifiers. However, there's no way to mitigate that kind of collision.If you need to support both TS 4.7 and TS 4.8, my recommendation would be to do as you have described in the workaround, or to branch based on
ts.versionorts.versionMajorMinor. Note that #50343 will likely further break compatibility here in favor of producing expected build breaks when accessingdecorators, though TS 4.8 exports several functions that can help to access only the decorators or modifiers of a node:ts.canHaveModifiers(node)ts.canHaveDecorators(node)ts.getModifiers(node)ts.getDecorators(node)To bridge between 4.7 and 4.8, I would recommend you have something like the following in your code:
frigus02 commentedon Aug 22, 2022
Thanks for looking into this. I was indeed hoping you could allow
ModifierLike[]for themodifiersparameter. But your explanation makes sense.We're going to use the workaround and some of the helpers you suggested.
I think this issue can be closed.
frigus02 commentedon Aug 22, 2022
Ron Buckton (@rbuckton) I just noticed that
canHaveModifiersandcanHaveDecoratorsare@internal. Are they supposed to be public?rbuckton commentedon Aug 22, 2022
Ah, yes they are. #50399 should fix that.