-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[feature request] Support Custom Types for Tagged Template Expressions #16551
Comments
This is very much related to #3136. To be frank, I don't know how ready we are to implement something like this. I think it'd be extremely useful, but it's a fairly large change that I'm not sure we could commit to any time in the near future, but I'd be open to hearing others' thoughts. |
True, this is closely related to #3136, but I think it's a stronger use case. You can always use code generation to generate strongly typed APIs for remote services. The key difference here is that we would be allowing users to stick with the native language. |
Seems like this would be best suited to a Language Service Plugin. @mjbvz has been doing a lot of great work recently to provide intellisense and syntax highlighting for tagged template literals. @mjbvz: Do you know of anyway using the current Language Service Plugin API to provide return type safety to tagged template literals? Or would it need to be a completely new feature added to the API? I'm trying to piece together a much easier (and feature complete) VS Code extension + Language Service Plugin for GraphQL. |
Not sure if a plugin can modify TypeScript's typing information. @RyanCavanaugh would know more about this. One thing to keep in mind is that plugins are currently focused on enhancing the editor experience. I do not believe they are loaded when you run |
Thanks for the reply @mjbvz -- my current approach is going in the direction of a VS Code plugin that interfaces with the language service to create type definitions and then insert references to them into the current document. For example: const foo = graphql`
query { ... }
` The VS Code plugin figures out the type information for the given query, and then creates a new file with the type interface defined in a subdirectory of the original file, so in this case you end up with the following file structure:
The original file (Foo.ts) is modified via the VS Code plugin to add the relevant import and reference as such: import { QueryResult } from './__generated__/Foo.queries'
const foo = <QueryResult>graphql`
query { ... }
` It's complicated, but the end result does work well for type safety. Hope to polish it all up and release soon. |
I'd like to revisit this. I've used the code generation solutions like @jayrylan mentions, but I find them to be a bit too complicated. It was something of an effort to set up, it's annoying to have to run a watcher process or install an editor plugin and try to figure out what went wrong if the typings are incorrect or fail to generate. The generators I've used also all rely on query and fragment names not colliding, since the generator dumps all of them into the same massive types file. I find it's a speed bump to educate new project contributors about what is going on (why import the query from here, but the typings from there) even if they understand TypeScript itself. And at the core of it, it just feels a little... wrong... to have the promises of typing from TypeScript, and a strongly typed API from GraphQL, but they just don't work together without a bunch of duct tape. Before finding this issue to tag along to, my original idea for a solution was to invent a new keyword for types which are dynamically generated from generics. generatedType GraphQLResult<TDoc extends GraphQLDocument> = (doc: TDoc) => {
const ast = parseGraphQLDocument(doc);
return walkASTAndConvertToTypeScriptTypes(ast);
};
function graphQLRequest<TDoc extends GraphQLDocument>(doc: TDoc): GraphQLResult<TDoc> {
// ...
} Obviously there's a lot of difficulties there. Presumably TypeScript would remove the However, I do like the approach in general, because the generated type could be bundled up into a library (like one that makes GraphQL requests) and the user would just get full typing without even having to think about it. I also think the concept may be useful outside of just templates. For instance, typing this function: function camelCaseKeys<T extends {}>(t: T): CamelCased<T> { /* ... */ }
camelCaseKeys({ A: 0, FooBar: 1 });
// { a: 0, fooBar: 1 } I get that this feature would probably be massively difficult, probably even more so than I'm aware. Perhaps not even possible with the way TS works today. But I could see it also being a huge step forward in seamlessly typing more things. |
Any news? |
Problem Statement
It is common to embed queries in tagged template expressions within typescript. For example, you might use sql:
You also see a similar pattern with graphql:
Currently, there is no way to provide type information about what is returned by
queryGraph
/querySQL
. A lot of potential type information is lost at the boundary here.I obviously don't expect typescript to read the graphql or SQL schema, as that's way out of scope. What I would like is a way to provide this information as a module author.
Proposal
I believe that all that's needed is a way to write plugins that answer the question "given a tagged template expression, what type does it return". This would only affect the type checker. It would not change generated code or add any new syntax.
A new
compilerConfig
option calledtaggedTemplateHandlers
would be added, that would take an array of paths to typescript files. An example might look something like:You could then define
querySQL
like:Language Feature Checklist
taggedTemplateHandlers
has been registered for that tagtaggedTemplateHandler
if one exists.TypeNode
returned by thetaggedTemplateHandler
in place of the default behaviour.I'm happy to do my best to help implement this, but I would need some pointers on where to start.
P.S. would it be possible to pass in the type of the expressions, in place of the actual expressions themselves?
The text was updated successfully, but these errors were encountered: