Skip to content

Commit 7462e73

Browse files
committed
fix(jsx): report a clear error when a component returns an array
A function component returning an array failed with "str.search is not a function". The return value did not match any branch in JSXFunctionNode.toStringToBuffer() and fell through to escapeToBuffer(), which expects a string, so the message pointed at an internal helper instead of the code that has to change. Returning an array is still not supported -- the type layer already rejects it -- so detect the case and throw a message that names the problem and the fix.
1 parent 224d2f5 commit 7462e73

2 files changed

Lines changed: 16 additions & 0 deletions

File tree

src/jsx/base.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,12 @@ class JSXFunctionNode extends JSXNode {
289289
buffer.callbacks ||= []
290290
buffer.callbacks.push(...res.callbacks)
291291
}
292+
} else if (Array.isArray(res)) {
293+
// Reaching `escapeToBuffer()` with an array fails with an unrelated message,
294+
// so report what the caller actually has to change.
295+
throw new Error(
296+
'A function component must not return an array. Wrap the elements in a Fragment: <>...</>'
297+
)
292298
} else {
293299
escapeToBuffer(res, buffer)
294300
}

src/jsx/index.test.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,16 @@ describe('render to string', () => {
171171
expect(template.toString()).toBe('<p><span>a</span><span>b</span></p>')
172172
})
173173

174+
it('Should throw when a component returns an array', () => {
175+
const Item = ({ x }: { x: number }) => <span>{x}</span>
176+
const Items = () => [0, 1].map((x) => <Item key={x} x={x} />)
177+
// @ts-expect-error a component returning an array is not a valid JSX element
178+
const template = <Items />
179+
expect(() => template.toString()).toThrow(
180+
'A function component must not return an array. Wrap the elements in a Fragment: <>...</>'
181+
)
182+
})
183+
174184
it('Empty elements are rended without closing tag', () => {
175185
const template = <input />
176186
expect(template.toString()).toBe('<input/>')

0 commit comments

Comments
 (0)