Reputation: 7618
That is, I know that when you write tag`Foo ${'bar'}.`;
, that’s just syntactic sugar for tag(['Foo ', '.'], 'bar');
.¹
But what about just `Foo ${'bar'}.`;
? I can’t just “call” (['Foo ', '.'], 'bar');
. If I already have arguments in that form, what function should I pass them to?
I am only interested in the native function that implements the template literal functionality. I am quite capable of rolling my own, but the purpose of this question is to avoid that and do it “properly”—even if my implementation is a perfect match of current native functionality, the native functionality can change and I want my usage to still match. So answers to this question should take on one of the following forms:
The name of the native function to use, ideally with links to and/or quotes from documentation of it.
Links to and/or quotes from the spec that defines precisely what the implementation of this function is, so that if I roll my own at least I can be sure it’s up to the (current) specifications.
A backed-up statement that the native implementation is unavailable and unspecified. Ideally this is backed up by, again, links to and/or quotes from documentation, but if that’s unavailable, I’ll accept other sources or argumentation that backs this claim up.
raw
property, since it’s a TemplateStringsArray
rather than a regular array, but I’m skipping that here for the sake of making the example more readable.I am trying to create a tag function (tag
, say) that, internally, performs the default template literal concatenation on the input. That is, I am taking the TemplateStringsArray
and the remaining arguments, and turning them into a single string that has already had its templating sorted out. (This is for passing the result into another tag function, otherTag
perhaps, where I want the second function to treat everything as a single string literal rather than a broken up template.)
For example, tag`Something ${'cooked'}.`;
would be equivalent to otherTag`Something cooked.`;
.
The definition of tag
would look something like this:
function tag(textParts, ...expressions) {
const cooked = // an array with a single string value
const raw = // an array with a single string value
return otherTag({ ...cooked, raw });
}
Defining the value of raw
is fairly straightforward: I know that String.raw
is the tag function I need to call here, so const raw = [String.raw(textParts.raw, ...expressions)];
.
But I cannot find anywhere on the internet what function I would call for the cooked
part of it. What I want is, if I have tag`Something ${'cooked'}.`;
, I want const cooked = `Something ${cooked}.`;
in my function. But I can’t find the name of whatever function accomplishes that.
The closest I’ve found was a claim that it could be implemented as
const cooked = [expressions.map((exp, i) => textParts[i] + exp).join('')];
This is wrong—textParts
may be longer than expressions
, since tag`Something ${'cooked'}.`;
gets ['Something ', '.']
and ['cooked']
as its arguments.
Improving this expression to handle that isn’t a problem:
const cooked = [
textParts
.map((text, i) => (i > 0 ? expressions[i-1] : '') + text)
.join(''),
];
But that’s not the point—I don’t want to roll my own here and risk it being inconsistent with the native implementation, particularly if that changes.
Upvotes: 5
Views: 943
Reputation: 19646
This implementation seems to match the behaviour of the built-in syntax pretty well. The test case throws a lot of nonsense at both implementations and it seems to pass:
function example<TValues extends unknown[]>(
parts: TemplateStringsArray,
...values: TValues
): string {
return parts
.flatMap((part, i) =>
i < values.length ? [part, String(values[i])] : [part],
)
.join('');
}
describe('example', () => {
it('produces a string that matches the behaviour of the built in version', () => {
expect(
example`a complex * ${'string'} with some funky stuff going on\n\r\s
\${}${1}${2}${'3'},${{ foo: 'bar' }},${['biz', 1, {}]}${null}${undefined}
$$1$1$24Ω≈ç√∫˜µ≤≥÷`,
).toEqual(
`a complex * ${'string'} with some funky stuff going on\n\r\s
\${}${1}${2}${'3'},${{ foo: 'bar' }},${['biz', 1, {}]}${null}${undefined}
$$1$1$24Ω≈ç√∫˜µ≤≥÷`,
);
});
});
Upvotes: 1
Reputation: 944186
The name of the native function to use, ideally with links to and/or quotes from documentation of it.
There isn't one. It is syntax, not a function.
Links to and/or quotes from the spec that defines precisely what the implementation of this function is, so that if I roll my own at least I can be sure it’s up to the (current) specifications.
Section 13.2.8 Template Literals of the specification explains how to process the syntax.
Upvotes: -1