What is the API story for this new codebase? #455
Replies: 24 comments 54 replies
|
What are your IPC plans for WebAssembly in the browser? |
|
Have you considered WASM as a solution to providing a cross-language API? I haven't used it for this purpose, but it seems like there could be a good match in requirements. WASM modules can pass typed data to one another, call one another's functions, etc. |
|
How's the story for TypeScript plugin developers and people integrating with the language service? More specifically, will method patching still work? The official way to create a plugin is to patch methods. And across such use cases there are probably dozens of cases where people reach into TypeScript semi-private internals to patch other methods (so that things can be intercepted for example) - will that also still work? If not, how do you envisage plugin authors to migrate away from doing that? |
|
I've used the tsc api for various codegen purposes, will you be exposing an API to walk/visit the AST tree as was available in the js tsc api? |
|
Will error reporting change? For a long time, TS errors have been a heated topic and there have been efforts by the community (https://github.com/yoavbls/pretty-ts-errors) to make it a little better. Will solutions like Pretty TS still work in the new world? |
|
Are there plans about instead of IPC there would be something like FFI? |
|
Not a question, but an observation: Right now, lots of tools which depend on types (TypeScript Eslint, Typia, etc) run their own Lexer, parser and type checker. It is not uncommon to have separate type checkers running in the ESLint process, in a development server and in the TypeScript language service. This leads to doing a lot of work twice or more and can also lead to inconsistencies if the tooling does some weird stuff. With an IPC layer it could become very feasible to have all of these hook into one tsgo process and have one source of truth for type information, meaning that the development experience when using these kinds of tools could get a lot smoother. Maybe this is something that can be considered when designing the IPC layer - i.e. to allow having one tsgo "server" and multiple clients consuming it's API. |
|
Is now maybe the time to also re-consider adopting semver from the API perspective? I could usually care less about breaking changes from the language and type checking perspective, but I would love it if from the tooling perspective we could get some sort of guarantees of what versions of the typescript api are supported and compatible. I will acknowledge that in the past this was a harder sell because of the nature of javascript and how the entire AST and compiler internals are essentially all public api. As a result, any change or internal refactoring could therefore be considered a breaking change, and thus nothing was. If the team is being more intentional about what is exposed across the API boundary, it can be more reasonable. My ideal would be something like: Note: changes to the language that add new features may change the resulting AST that is returned from the API. This should not be considered a breaking change to the API, but maybe things like removing documented properties from existing nodes, might be? That way, tooling providers can set their expectations of supported typescript releases based on the |
|
Hey there, I'm developing an experimental Node.js binding here: https://github.com/Brooooooklyn/typescript-go-napi/tree/main/rust The basic idea is to compile typescript-go into a static link library, and then wrap it into a JavaScript API in Rust using NAPI-RS. I have now completed two basic APIs, among which transform is like this: import { transform } from '@typescript-go/api'
transform('const a: number = 1;', '/absolute/path/a.ts')
// 'const a = 1;\n' |
How future-proof is this module? Webdriverio badly wanted to provide a sync API for writing tests, and relied on |
|
Adding my two cents here, if API is not possible for major languages (mainly JS and probably Rust for SWC/OXC), a static type info snapshot can also be helpful. (though it is not possible to do transformation) Related issues https://github.com/microsoft/typescript-go/issues/504 |
|
Would it be possible to use tsc-go as a library from Go and hook into it that way? As opposed to plugins and IPC etc? |
|
The TypeDoc project uses TypeScript compiler APIs (including watch-related APIs) to generate documentation from source projects (via JSDoc as well as TypeScript type info) and to respond to changes in the code base and non-code documentation files. Will the same or substantially similar watch APIs be available from JS? (i.e. including the ability to add arbitrary watches as well as incremental-compile-on-change) |
|
The beginnings of the IPC API are now in a PR at #711. |
|
However the API is implemented, it would be great if the TS Compiler, Language Service, etc APIs were better documented and provided more detailed and complex examples than the currently limited wiki pages. Sample integrations and such could also be very useful. Per microsoft/TypeScript#49790, microsoft/TypeScript#49050, and links therein, I've had to dive into the source code on numerous occasions to understand how to use pieces of the API and fix implementation issues, and sometimes haven't even been able to find an answer there either. This makes maintaining an integration really difficult in certain areas as there's little-to-no information to be found on proper usage, especially when it comes to various edge-cases like |
|
One limitation I've encountered as a (very early!) consumer of the API is that concurrency is not doable, in that due to the nature of pipes, I have to wait to consume a response from stdout before sending another request via stdin. I'd ideally want them to be able to operate independently. Is there any plan to address this? Could use an uds socket over stdin or maybe even correlation ids? I was originally designing my API around async processing, but I'm switching to a mpsc approach with tsgo subprocess running in a dedicated thread. If the goal is for tsgo to become the canonical source of truth with multiple processes hooking into its API with it serving as more of a server, it'd be great to support a more traditional client-server architecture. UDS would be a good middlepoint between the overhead of tcp sockets |
|
One thing that would be nice (and I apologize, I don't mean to turn this into a feature request thread) off the top of my head is the ability to pass an AST directly to the api server. The big blocker for rust-based plugins like oxlint, biome, etc is the inconsistent mapping between their CST/AST and TS's AST (see typescript-eslint for the magic they do to convert back and forth). I could imagine an universe where a plugin creates their own internal AST, converts it to a TS AST (with an mapping from their nodes -> TS nodes), and then passes it directly to the API. Then, the linter can query the nodes they're interested in type information about directly without having to interpret typescript's AST back to theirs. The big blocker in the ecosystem from what I see is how ts interprets trivia in terms of leading spaces etc, which shouldn't matter for type-checking. Basically, give tsgo the ability to deserialize an encoded |
|
Since EDIT: got simple diagnostics working |
|
Just wondering: Is there still no way to use the new TypeScript Go Compiler to print an AST e.g. as JSON? I don't need to modify nodes or transform anything. I just want the parsed AST from the compiler on stdout. Possible/Not possible? |
|
Had a poke at the new API (directly, not via the node package) and while checking to see if I could do a full VFS found it currently barfs if you give it a CWD that doesn't exist or return Hoping to eventually wire up a UX to this so you can poke around in a build and see exactly what is taking time a lot easier: it's no good being 10x faster, if that just means you make 10x more expensive types :P |
|
Different angle on this. I'm working on The shim approach is borrowed from Plugins ship as Go source. puchm The shim is an overlay I maintain by hand, but the AST and checker surfaces have been stable enough in practice that tsgo bumps haven't been a serious cost. Unlike the |
|
I'm making a compiler in Go that needs to parse ASTs of type declaration files. Is there a way to do that from Go? |
|
I tested the current project-backed native AST against the published After mechanical compatibility adapters, 7/7 valid fixtures convert strictly to ESTree, including JS, JSX, comments, generics, This narrows the syntax-only tooling request considerably. We do not appear to need the full legacy compiler API or matching numeric enum values. The remaining blocker is one isolated parsing operation: api.parseSourceFile({
fileName,
text,
scriptKind,
languageVersion,
setParentNodes: true,
})
// -> { sourceFile, diagnostics }The operation would:
An optional batch form could reduce IPC overhead: api.parseSourceFiles(requests)The project-backed model in https://github.com/microsoft/typescript-go/issues/2824 is appropriate for typed linting and semantic tools. It does not replace the syntax-only Executable evidence and the detailed minimal proposal are here:
Would an isolated |
|
I have a stronger downstream integration result to add to the earlier isolated-parser proposal. The previous experiment proved that the project-backed native parse(sourceText, options);
parseAndGenerateServices(sourceText, options);I loaded Results:
Evidence:
This narrows the required integration surface further: the syntax-only public parser APIs do not need redesign. They currently reach one replaceable runtime dependency, The temporary-project facade is not proposed as the solution—it still creates an API process, project, and |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
How will the API work? Will developers have a canonical JavaScript-based API for integrating with this new version of TypeScript?
While we are porting most of the existing TypeScript compiler and language service, that does not necessarily mean that all APIs will be ported over. Because of the challenges between language runtime interoperability, API consumers will typically not communicate within the same process. Instead, we expect our API to leverage a message-passing scheme, typically over an IPC layer. Because this sort of bridging is not "free", exposing all functionality will be impractical. We expect to have a more curated API that is informed by critical use-cases (e.g. linting, transforms, resolution behavior, language service embedding, etc.).
We knew that providing a solid API would be a big challenge, so as soon as we started exploring the TypeScript port, we investigated the possibilities here. Beyond how capable the API would be, we asked ourselves whether the sorts of use-cases would be constrained by the performance of IPC solutions. More specifically, even if we could come up with a set of APIs that did what users wanted, would the throughput of requests be a limiting factor? Would the new TypeScript be fast enough to offset the cost of serialization and data transfer? Would the chattiness of API usage overwhelm the wins of having a much faster compiler?
We've become increasingly confident and optimistic in answers around the IPC performance. Kat Marchán (@zkat) has built a Node native module to use synchronous communication over standard I/O between external processes. Building on that, Andrew Branch (@andrewbranch) has experimented with exposing an API server entrypoint to our compiler, along with a JavaScript client that "speaks" to the server over that communication layer. What we've found is fairly promising - while IPC overhead is not entirely negligible, it is small enough. We also can imagine opportunities to optimize, use other underlying IPC strategies, and provide batch-style APIs to minimize call overhead.
As our experiments solidify, we will post more concrete details on our plans, and what the API will look like.
All reactions