2 ms·
Is it me or are Tagged templates a recipe for hard to read code? Just the way it extracts the substrings into arguments for unpredictable strings. It doesn't t
by dmix 4y ago
Is it me or are Tagged templates a recipe for hard to read code?
Just the way it extracts the substrings into arguments for unpredictable strings. It doesn't translate to readable code.
I'd much rather use repetitive template strings. Unless I was doing some really fancy string manipulation. Or make my own functions with explicit arguments.
- deleted 4y ago[deleted]
- tobr 4y agoMatching up the template strings with the values is a little wonky because there’s always one more string than value. But it’s pretty rare that you’d write lots of different tagging functions, usually you write a generic one to use with many different types of templates. Tucking away complexity into a function to make nice and easy-to-use templates is a reasonable trade off I think.
- deleted 4y ago[deleted]
- renlo 4y agoThey've allowed "styled-components" to work though, which is pretty nice. I always thought of them as providing a way to parse DSLs directly in your code. For example, a fictional way to generate some config could look like this (using tagged templates): const thingies = ["a", "b"]; const config = yaml` - foo - bar - baz - thingies: ${thingies.map(thing => yaml`- thing: ${thing}`)} `; // config = ["foo", "bar", "baz", { "thingies": [{"thing": "a"}, {"thing": "b"}] }] At a company I worked at people were generating YAML using Jinja templates, but tagged templates to me would be a better approach. Is it hard to read? It can be, but compared to the alternatives it's not too bad.
- monkpit 4y agoconst thingies = ["a", "b"]; const thingToYaml = thing => yaml`- thing: ${thing}` const thingiesYaml = thingies.map(thingToYaml) const config = yaml` - foo - bar - baz - thingies: ${thingiesYaml} `; It doesn’t have to be hard to read
- shhsshs 4y agoIn this example, why use YAML at all?... const thingies = ["a", "b"]; const config = [ "foo", "bar", "baz", { thingies: thingies.map(thing => ({ thing })), }, ] // config = ["foo", "bar", "baz", { "thingies": [{"thing": "a"}, {"thing": "b"}] }]
- zeroonetwothree 4y agoRight, it's not a great example since yaml is intentionally equivalent to JS objects.
- lloydatkinson 4y agoWell, styled components also has a plain object syntax which I think a lot of people prefer me included.
- tracker1 4y agoTo me, the single best example, is a function that turns a template into a parameterized query, and then makes an async database request... var result = await query` SELECT * FROM foo.bar where baz = ${baz} `; There are libraries that allow for construction of queries as well using template strings. I don't know of too many instances beyond this where there's custom functions for tagged templates, vs just string building with parameters.
- tofuahdude 4y agoCan confirm. This is the best use case I've come across. You can dynamically compose queries and not even think about argument positioning. No concern about injection. Better performance than named variables that are translated into positional.
- jmull 4y agoI agree this is pretty much the best example of this feature in action... which is why I don't think it should have been made a language feature. It's nifty, but not nearly better enough to justify its existence, IMO. Here's the alternative: var result = await query( 'SELECT * FROM foo.bar where bar = :baz', {baz} ); I get it... there's that extra level of indirection. But people are working hard, as we speak, to abuse the feature.
- justeleblanc 4y agoI'd rather have the language settle on one single templating syntax rather than every library and their son bake a half-assed one. "Oh, does query use the : syntax? The $ one? Does it take the template string first, or the arguments?" And with your example, `query` needs to figure out how to parse the string, extract the template slots, and pass the correct arguments into the correct slots. It's a recipe for disaster if every library needs to reimplement that.
- jmull 4y agoWell, people could settle on a common templating syntax without making it a language feature. The fact that they haven't tells you it's not that important, relative to other concerns. It's not like "figure out how to parse the string, extract the template slots, and pass the correct arguments into the correct slots" is rocket science. And it's not like people are going to rewrite the numerous existing libraries for this kind of thing. The new tagged-template APIs are going transform their arguments and call the existing APIs. I guess it's nice that new Javascript-specific templating languages can have common escaping syntax. It's just hard to get excited about the 15th standard.
- frob 4y agoI find them to be really useful for simple and targeted tasks. For example, simplur[1] for pluralizing strings and dedent[2] just for developer ergonomics. [1] https://www.npmjs.com/package/simplur https://www.npmjs.com/package/simplur [2] https://github.com/dmnd/dedent https://github.com/dmnd/dedent
- conaclos 4y agoIs there a difference between dedent`something ${code}` and dedent(`something ${code}`) ? Not sure to understand the advantage of tagged strings here...
- mhink 4y agoThe difference is on the tag side. "Tag functions" receive the string segments separately from the interpolated values, so like: function exampleTag(stringSegment, ...values) { console.log(stringSegment); console.log(values); } const myNumber = 123; exampleTag`foo ${myNumber} bar ${myNumber}`; // Prints: // ['foo', 'bar', ''] // [123, 123] This gives the tag function a way to access the interpolated values themselves, before they get coerced to a String. You're correct, though, that it really doesn't make much of a difference for a dedent function.
- tczMUFlmoNk 4y agoIt is actually important for a dedent function when the interpolands contain newlines. Consider this example: function fmt(q, a) { return dedent`\ Question: ${q} Answer: ${a} `; } Since `dedent` is basically syntactic sugar for developer convenience, we want this function to be equivalent to this: function fmtDesugared(q, a) { return `Question: ${q}\nAnswer: ${a}\n`; } Now consider this input: console.log(fmt("a\nb", "c\nd")); // should print: Question: a b Answer: c d But if `dedent` only got to see the string after interpolation—like this— function fmtWrong(q, a) { return dedent(`\ Question: ${q} Answer: ${a} `); } then the input to `dedent` would be Question: a b Answer: c d and so `dedent` would not strip any indentation. That is, `dedent` is meant to identify the maximal common leading indentation in the template as written by the developer, which should not depend on the values of the interpolands. A stale GitHub issue on the dmnd/dedent repo has a real-world example where this matters and led to a subtle bug: https://github.com/dmnd/dedent/issues/22 https://github.com/dmnd/dedent/issues/22
- culi 4y agoI love tagged templates and am so relieved to finally have something like Perl/Ruby/PHP's heredocs. We should be able to write multi-line strings without having to break our linter's tab rules or write some silly post processing function!