microsoft / microsoft/TypeScript
[feature request] Support Custom Types for Tagged Template Expressions
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Go
- Sterne
- 111k
- Forks
- 14.4k
- Ø Merge
- 1 T. 19 Std.
- Gemergte PRs (30 T.)
- 117
Beschreibung
Problem Statement
It is common to embed queries in tagged template expressions within typescript. For example, you might use sql:
const result = await querySQL(sql`SELECT * FROM users WHERE id = ${userID}`);
You also see a similar pattern with graphql:
const result = await queryGraph(graphql`query { user { id, name } }`);
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 called taggedTemplateHandlers would be added, that would take an array of paths to typescript files. An example might look something like:
import {parseSqlQuery, convertSqlTypeToTypeScriptType} from 'sql-helpers';
import * as ts_module from "typescript/lib/tsserverlibrary";
export default {
tag: 'sql',
templateHandler(modules: {typescript: typeof ts_module}, strings: string[], ...expressions: Array<ts_module.Expression>) {
const ts = modules.typescript;
const fields = parseSqlQuery(strings.join('"EXPRESSION"'));
return ts.createTypeReferenceNode(
ts.createIdentifier('SqlQuery'), // typeName
ts.createNodeArray([ // typeArguments
ts.createTypeLiteralNode(Object.keys(fields).map(field => {
return ts.createPropertySignature(
ts.createIdentifier(field),
undefined, // question token
convertSqlTypeToTypeScriptType(fields[field]), // type
undefined, // initializer
)
}))
])
);
}
};
You could then define querySQL like:
define function querySQL<TResult>(query: SqlQuery<TResult>): Promise<TResult>;
Language Feature Checklist
- Syntactic - no new changes
- Semantic
- When a tagged template is encountered by the type-checker
- See if a
taggedTemplateHandlershas been registered for that tag - Call that
taggedTemplateHandlerif one exists. - Use the
TypeNodereturned by thetaggedTemplateHandlerin place of the default behaviour.
- See if a
- When a tagged template is encountered by the type-checker
- Emit - no new changes
- Compatibility - no new syntax is added/changed, so it should be fully backwards/forwards compatible.
- Other
- I expect there will be some performance impact, but hopefully the fact that both plugins and the compiler are written in typescript should make this minimal.
- Ideally, this information would be used for autocomplete helpers as well as in the typechecker, I do not know if that would require extra work.
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?
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Das Issue nennt keine Dateien, Tests oder Einstiegspunkte. Beginne damit, die Typprüfung von tagged-template und die Verarbeitung von compilerConfig zu lokalisieren, und ermittle anschließend, wie ein handler einen Rückgabetyp bereitstellen könnte, ohne emit zu beeinflussen; als abgeschlossen gilt die Implementierung und das Testen des vorgeschlagenen Konfigurations- und type-checker-Verhaltens.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- typescript
- Bereich
- compilers
- Issue-Typ
- Feature
- Schwierigkeit
- 5/5
- Geschätzter Aufwand
- Über eine Woche
- Aktivitätsstatus
- Veraltet
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 25/100