Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing function signatures in typescript.d.ts #40507

Closed
arocheleau opened this issue Sep 11, 2020 · 8 comments · Fixed by #41810
Closed

Missing function signatures in typescript.d.ts #40507

arocheleau opened this issue Sep 11, 2020 · 8 comments · Fixed by #41810
Assignees
Labels
API Relates to the public API for TypeScript Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@arocheleau
Copy link

TypeScript Version: 4.0.2

Search Terms: getMutableClone cloneNode createThrow createNew NodeFactory

Code

ts.factory.cloneNode(someNode);

Expected behavior:

The compiler should compile the code just fine without error.

Actual behavior:

The compiler signal an error saying that the cloneNode function does not exists on NodeFactory.

On ts.getMutableClone the deprecated notice says we should use factory.cloneNode instead. Unfortunately, there is no cloneNode function defined on NodeFactory according to the declaration file (typescript.d.ts).

However, if I trick the compiler with the following code, I see that a cloneNode function do exist on the object that implements the NodeFactory interface at runtime.

(ts.factory as any).cloneNode(someNode);

Related Issues:

I have seen a few deprecated notices that are a bit misleading on many functions in the ts namespace. I have not checked all functions, but to name a few:

  • createThrow says to use factory.createThrow instead of factory.createThrowStatement.
  • updateThrow says to use factory.updateThrow instead of factory.updateThrowStatement.
  • ...
  • The same goes for createNew, updateNew, createTry, updateTry
@DanielRosenwasser DanielRosenwasser added API Relates to the public API for TypeScript Needs Investigation This issue needs a team member to investigate its status. labels Sep 12, 2020
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 4.1.1 milestone Sep 12, 2020
edsrzf added a commit to edsrzf/ts-migrate that referenced this issue Oct 24, 2020
Most ts.create* and ts.update* functions are deprecated as of TypeScript 4.0. The
current plan is to emit noiser and noisier warnings with each version
until the deprecated functions are removed in 4.3.

See this pull request for more details:
microsoft/TypeScript#35282

Some method signatures and names have changed slightly.

The easy way to update is to use the global ts.factory object.
TypeScript transformations also have access to a NodeFactory in their
transformation contexts.

Note that we still use the deprecate getMutableClone function because
its replacement is not included in the TypeScript declarations. See
microsoft/TypeScript#40507
@longlho
Copy link
Contributor

longlho commented Oct 24, 2020

same with createObjectLiteral, createCall, createArrayLiteral as well :( nvm they're renamed, the comment seems to be inaccurate then

@brad4d
Copy link

brad4d commented Nov 26, 2020

I hit this today while trying to update tsickle to use the new NodeFactory API.
I need to use nodeFactory() to replace getMutableClone(), but cannot.
The misleading method names were annoying, but I was able to find the ones I needed.

Is this likely to be fixed in a 4.0.x release?
I'm tempted to put off the whole migration of tsickle to NodeFactory until this is fixed so I don't end up with partially migrated code.

@rbuckton
Copy link
Member

rbuckton commented Dec 3, 2020

getMutableClone wasn't safe to use, in general, since AST nodes should be treated as if they are immutable. I don't recommend using cloneNode as isn't all that safe to use either, and I've been trying to reduce its use within the compiler itself. You're generally better off using one of the update methods if you need to get an updated Node. The most of the uses of cloneNode in the compiler today are to essentially clone identifiers for unique comment/source map positions, which I intend to clean up.

What are your use cases for getMutableClone that aren't served by the various update methods?

@rbuckton
Copy link
Member

rbuckton commented Dec 3, 2020

I'd like to further clarify why cloneNode shouldn't be used and isn't available in the published API. In the TypeScript compiler we track the set of necessary transformations on a Node using a bitmask known as TransformFlags. Prior to 4.0, we would dynamically compute the transform flags for a Node during bind and whenever returning from a call to visitNode or visitNodes, however we've had multiple issues in the past with flags not being calculated in certain cases.

When we refactored the node factory API so that we could use it in the parser, we changed the behavior so that we calculate these transform flags as the tree is created. The logic behind how these flags are calculated is now baked into the various create... (and update...) methods on the factory. If you previously used getMutableClone to copy a node so that you could replace a child (which was the case in several places in the compiler), transformation flags would no longer be correctly calculated. While cloneNode does copy the transform flags of the source node, if you were to attempt to use it in the fashion I just described it would result in incorrect emit. Since this is a practice we'd like to discourage (which is why most child nodes in the TypeScript AST are now readonly), we elected to not make cloneNode available as part of our public API.

The only safe use of cloneNode would be to clone a keyword, token, identifier, or literal. If we do make it public, it will likely only be available for use with those specific cases.

@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Dec 3, 2020
@rbuckton
Copy link
Member

rbuckton commented Dec 3, 2020

I just put up a PR that fixes the messages, though it does not expose cloneNode as I still need further information on existing getMutableClone use cases.

@longlho
Copy link
Contributor

longlho commented Dec 4, 2020

So the use case that we have to it is effectively ease of use: With cloneNode we can freely manipulate its children regardless of type & depth while with update* API it seems like we've have to return a new visitor that does the traversal & update separately. Coupled that w/ the fact that if we want to pass some parent state to the visitor we've have to hoist/nest it.

In general I've already rewritten our suite of transformers to the update* API so it's ok :) It certainly makes transformer maintenance a little trickier.

The babel AST manipulation is a little more ergonomic in this aspect.

@edsrzf
Copy link

edsrzf commented Dec 5, 2020

Here's a use case for getMutableClone/cloneNode that I've had:

https://github.com/airbnb/ts-migrate/blob/8c1f8c1e48d43f7bc6f9e03cf7f8ba743ac5257c/packages/ts-migrate-plugins/src/plugins/member-accessibility.ts#L80-L84

I have a ClassElement of some kind and I want to update only its accessibility modifier. Without cloning, I have to figure out which specific type of class element I have (PropertyDeclaration, MethodDeclaration, GetAccessor, or SetAccessor) and call its respective update function. It's doable, but it's significantly more verbose and less convenient.

edsrzf added a commit to edsrzf/ts-migrate that referenced this issue Dec 8, 2020
This function is deprecated and is not currently slated to be replaced.

The new code is much more verbose, but there doesn't appear to be any
real alternative.

See microsoft/TypeScript#40507
@arocheleau
Copy link
Author

In my case, the fact that the old API had a getMutableClone function make me doubt that the AST nodes were truly immutable and so I was cautious when it was time to mutate nodes. My knowledge of the compiler internals is limited. I have built it from the few documentations I found, some blog posts, code examples, trials and errors and code tracing. Most of the documentation I found was minimal and refered to older versions, so it was probably outdated.

Anyway, in my application, I am cloning nodes at 2 places. One of the 2 place is already using the update* functions and so, I guess I may safely remove the call to the cloning function since, the way I understand it, the update* functions are returning new immutable nodes.

For the other place, I am unaware if I must clone the node or not. Without getting into details, let say that I am creating a tool for internal usage that generates a single dts file to expose our public API. I needed some private fields and functions to be removed from the dts since they are refering types that are not publicly available. Furthermore, most of theses types came from or were imported from packages that once bundled, are not accessible to the consumer. Basically, with the help of the TypeChecker, I identify the types that need to be part of our public API, extract their AST nodes, transform them and put them all in a single SourceFile.

I had an issue when I asked the Printer to generate the source code of this SourceFile made of AST nodes coming from different files. For example, the Printer did not generate the values of the enum members. After tracing the code, I figured out that the Printer tried to read the enum member values directly from the original source file and failed instead of consulting the AST nodes which have everything it needs.

In order to fix this issue, I created a transformer that removes all links or informations about the original source file. So I invoke the following functions on the nodes:

  • ts.setOriginalNode
  • ts.setTextRange
  • ts.setSourceMapRange
  • ts.setCommentRange

I don't know if these functions work like the update* functions and return a new immutable node or if it mutates it. Right now, I am just cautious and clone the node first.

Thank you

@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Dec 11, 2020
jasonreyes9 added a commit to jasonreyes9/ts-migrate that referenced this issue Oct 31, 2023
Most ts.create* and ts.update* functions are deprecated as of TypeScript 4.0. The
current plan is to emit noiser and noisier warnings with each version
until the deprecated functions are removed in 4.3.

See this pull request for more details:
microsoft/TypeScript#35282

Some method signatures and names have changed slightly.

The easy way to update is to use the global ts.factory object.
TypeScript transformations also have access to a NodeFactory in their
transformation contexts.

Note that we still use the deprecate getMutableClone function because
its replacement is not included in the TypeScript declarations. See
microsoft/TypeScript#40507
jasonreyes9 added a commit to jasonreyes9/ts-migrate that referenced this issue Oct 31, 2023
This function is deprecated and is not currently slated to be replaced.

The new code is much more verbose, but there doesn't appear to be any
real alternative.

See microsoft/TypeScript#40507
simonvarey added a commit to simonvarey/typescript-transformer-handbook that referenced this issue Dec 8, 2024
itsdouges pushed a commit to itsdouges/typescript-transformer-handbook that referenced this issue Dec 12, 2024
* Added package manager field to package.json

* Upgraded typescript to 5.7.2

* Replace deprecated ttypescript with ts-patch, temporarily changed build scripts

* Updated add-import-declaration for TS 5.7.2

* Updated create-unique-name for TS 5.7.2

* Updated my-first-transformer for TS 5.7.2

* Updated replace-node example for TS 5.7.2

* Removed update-mutable-node example as getMutableClone has been removed. See: microsoft/TypeScript#40507

* Updated update-node example for TS 5.7.2

* Updated find-parent example for TS 5.7.2

* Updated follow-imports example for TS 5.7.2

* Updated follow-node-modules-imports example for TS 5.7.2

* Updated hoist-function-declaration imports example for TS 5.7.2

* Updated hoist-variable-declaration imports example for TS 5.7.2

* Updated log-every-node imports example for TS 5.7.2

* Updated match-identifier-by-symbol imports example for TS 5.7.2

* Updated remove-node imports example for TS 5.7.2

* Updated return-multiple-node imports example for TS 5.7.2

* Started updating README for TS 5.7.2

* Fixed typo

* Continue updating README for TS 5.7.2

* Finished updating README for TS 5.7.2

* Reverse temporary changes to build scripts

* Removed accidently build JS versions of examples files, Small change to README
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Relates to the public API for TypeScript Fix Available A PR has been opened for this issue Needs Investigation This issue needs a team member to investigate its status. Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants