Repository navigation
[TS 4.8] Deprecated factory methods aren't usable with originalNode.modifiers #49939
Description
Activity
- addedNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.
on Jul 29, 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:
function tryGetDecorators(ts: typeof import("typescript"), node: Node) { if (typeof ts.getDecorators === "function") { // TS 4.8 and later return ts.canHaveDecorators(node) ? ts.getDecorators(node) : undefined; } // TS 4.7 and earlier return node.decorators; } function tryGetModifiers(ts: typeof import("typescript"), node: Node) { if (typeof ts.getModifiers === "function") { // TS 4.8 and later return ts.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. return ts.visitNodes(node.modifiers, node => ts.isModifier(node) ? node : undefined, ts.isModifier); }
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.
Ron Buckton (@rbuckton) I just noticed that
canHaveModifiersandcanHaveDecoratorsare@internal. Are they supposed to be public?Ron Buckton (@rbuckton) I just noticed that
canHaveModifiersandcanHaveDecoratorsare@internal. Are they supposed to be public?Ah, yes they are. #50399 should fix that.
Reacted by Jan Kühle and Braden Napier
Bug Report
Deprecated factory methods aren't usable with
originalNode.modifiers.#49089 changed
Node.prototype.modifiersfromNodeArray<Modifier>toNodeArray<Modifier | Decorator>. It also changed factory functions to accept a singleNodeArray<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 inoriginalNode.modifiers:🔎 Search Terms
4.8, modifiers, ModifiersArray, ModifierLike, decorators, Modifier, Decorator, factory
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
Note: Not sure how to reproduce this in the playground.
import from "typescript"doesn't seem to import nightly typings in the playground.💻 Code
🙁 Actual behavior
This code snippet fails to compile with the error message inlined in the snippet.
🙂 Expected behavior
Ideally the deprecated
factory.updateXxxfunctions would still be usable as before. This would make the upgrade to TypeScript 4.8 easier.I imagine most usages pass in
originalNode.modifiersunchanged, unless they modify the modifiers. Picking Angular as a random example:https://github.com/angular/angular/blob/557cf7dc63fe768900f296252e1a96e6166b24df/packages/compiler-cli/src/ngtsc/transform/src/transform.ts#L210
Workarounds
We can change usages of factory functions to make code compatible with both TypeScript 4.7 and 4.8 by doing something like: