-
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
feat(33304): Better type-safety with tagged template literals #45310
Conversation
…th no substitutions
The TypeScript team hasn't accepted the linked issue #33304. If you can get it accepted, this PR will have a better chance of being reviewed. |
|
Ah, interesting. That should be a simple change. |
} | ||
|
||
var a = tag `part\1${''}part\2`; | ||
var a: {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this here?
|
||
declare function dataTypes<TParts extends readonly string[], TArgs extends ArgsFor<TParts>>( | ||
parts: TemplateStringsArray<readonly [...TParts, '']>, | ||
...args: TArgs): unknown; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you make this return TParts
so we can witness the inference result?
Personally I'm hesitant to add more complexity to That said, it does feel like there should be a way to capture the contents of a template string today. |
@typescript-bot pack this |
Heya @DanielRosenwasser, I've started to run the tarball bundle task on this PR at 90345f8. You can monitor the build here. |
Hey @DanielRosenwasser, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
Well, in some sense, this PR is really intended to support "slow" DSL parsers; in particular, a library that I've been contributing to has wanted to support compile-time checking of template literals (and their parts) because of the particular API: const TEMPLATE = html`
<${MyComponent} prop:foo=${someValue} />
`; and there's no compile-time validation that |
@DanielRosenwasser from the design meeting notes, it sounds like we want to hold this PR to get more discussion on the issue. Is that correct? |
I took a look at the meeting notes #45504, and I did note this bit:
I am curious about what the right tool is then? There doesn't really seem to be a great alternative to doing this. In particular, the problem is that of run-time equivalence; the library is intended to be usable both with plain JS and TS. JSX cannot be used without compiling, and furthermore the use-case of safe HTML templates was among the original design considerations that TC39 looked at when adding this feature to the spec. Tagged template literals are a very natural API for native JS libraries (see also: graphql-tag, html tag). The approach taken by Svelte/Vue (custom language servers) or tsserver plugins doesn't really scale; writing transformers to turn syntax into JSX seems like a significant amount of work, especially for smaller projects. This approach also doesn't even allow for correctness checks at compile-time. |
Also a use case in the wild which currently suffers from this limitation: https://github.com/arcanis/graphql-typescript-integration and https://www.graphql-code-generator.com/docs/presets/gql-tag-operations
|
I just stumbled into this while experimenting so thought I'd toss in a "use-case". I'm creating value containers that have explicit names: const name = val`userName`(""); // type Val<"userName",string>
const age = val`userAge`(100); // type Val<"userAge",number>
const count = val``(0); Tagging names like this is useful since containers will be passed around and prop-drilled - the variable name I know there's a million ways to do this like I avoid variable names altogether like this: const state = pack(
val`name`("Willow"),
val`age`(100),
val`weekday`('Monday'),
)
// typeof state = { name: Val<"name", string>, age: Val<"age", number>, weekday: Val<"weekday", string> } So I can just do |
@DanielRosenwasser did we discuss this? If so, what was the outcome? I'm going through community PRs and trying to decide whether to keep it open. |
It was discussed at #45504. I think the outcome is that we're still not yet confident that we want to make this change, so for now I'm going to close this. We can revisit in the future if we ever change our minds. We do appreciate the PR though @BobobUnicorn. |
thanks for letting me know! |
This PR implements better type-checking for tagged template literals. The main change is that
TemplateStringsArray
is now generic over its string parts. In particular,TemplateStringsArray
is now:The type parameter has a default for backwards-compatibility.
This PR also includes compiler changes to pass the exact string parts as a tuple for inference.
Fixes #33304