diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/diagnostics-slots-imported.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/diagnostics-slots-imported.svelte index 2e7530a2c..f5e414741 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/diagnostics-slots-imported.svelte +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/diagnostics-slots-imported.svelte @@ -2,8 +2,10 @@ export let prop: any; const defaultSlotProp = 1; const namedSlotProp = true; + const spread = {a: true, b: ''}; {prop} + diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/expected.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/expected.json index 91997a60b..b6f2a9533 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/expected.json +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/expected.json @@ -33,5 +33,27 @@ "message": "Cannot find name 'namedSlotProp'.", "code": 2304, "tags": [] + }, + { + "range": { + "start": { "line": 13, "character": 39 }, + "end": { "line": 13, "character": 40 } + }, + "severity": 1, + "source": "ts", + "message": "Property 'd' does not exist on type '{ a: boolean; b: string; }'.", + "code": 2339, + "tags": [] + }, + { + "range": { + "start": { "line": 16, "character": 5 }, + "end": { "line": 16, "character": 13 } + }, + "severity": 1, + "source": "ts", + "message": "This condition will always return 'false' since the types 'boolean' and 'string' have no overlap.", + "code": 2367, + "tags": [] } ] diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/input.svelte index dbbf396d0..ec93ebbf3 100644 --- a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/input.svelte +++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/slot-typechecks/input.svelte @@ -11,4 +11,10 @@ {defaultSlotProp}

{namedSlotProp} +

+ {a === true} + {c === ''} + {a === ''} + {d} +

diff --git a/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts b/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts index d24cbf995..b663d8f52 100644 --- a/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts +++ b/packages/svelte2tsx/src/svelte2tsx/createRenderFunction.ts @@ -88,7 +88,11 @@ export function createRenderFunction({ Array.from(slots.entries()) .map(([name, attrs]) => { const attrsAsString = Array.from(attrs.entries()) - .map(([exportName, expr]) => `${exportName}:${expr}`) + .map(([exportName, expr]) => + exportName.startsWith('__spread__') + ? `...${expr}` + : `${exportName}:${expr}` + ) .join(', '); return `'${name}': {${attrsAsString}}`; }) diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/slot.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/slot.ts index 4cd6f1301..3ef5b650f 100644 --- a/packages/svelte2tsx/src/svelte2tsx/nodes/slot.ts +++ b/packages/svelte2tsx/src/svelte2tsx/nodes/slot.ts @@ -61,6 +61,12 @@ export class SlotHandler { return resolved; } + /** + * Returns a string which expresses the given identifier unpacked to + * the top level in order to express the slot types correctly later on. + * + * Example: {#each items as item} ---> __sveltets_1_unwrapArr(items) + */ private getResolveExpressionStr( identifierDef: SvelteIdentifier, scope: TemplateScope, @@ -168,6 +174,10 @@ export class SlotHandler { })); } + /** + * Resolves the slot expression to a string that can be used + * in the props-object in the return type of the render function + */ private resolveExpression(expression: Node, scope: TemplateScope) { let resolved = this.resolvedExpression.get(expression); if (resolved) { @@ -234,6 +244,14 @@ export class SlotHandler { if (attr.name == 'name') { continue; } + + if (attr.type === 'Spread') { + const rawName = attr.expression.name; + const init = scope.getInit(rawName); + const name = init ? this.resolved.get(init) : rawName; + attributes.set(`__spread__${name}`, name); + } + if (!attr.value?.length) { continue; } @@ -268,6 +286,7 @@ export class SlotHandler { if (attrVal.type == 'MustacheTag') { return this.resolveExpression(attrVal.expression, scope); } + throw Error('Unknown attribute value type:' + attrVal.type); } } diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/expected.tsx b/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/expected.tsx index f1218a3d8..7ab845809 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/expected.tsx +++ b/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/expected.tsx @@ -2,9 +2,9 @@ <>;function render() { /*Ωignore_startΩ*/;const __sveltets_ensureSlot = __sveltets_1_createEnsureSlot();/*Ωignore_endΩ*/ <>{__sveltets_1_each(items, (item) => <> - Hello + Hello )} -return { props: {}, slots: {'default': {a:__sveltets_1_unwrapArr(items), b:{ item:__sveltets_1_unwrapArr(items) }, c:{ item: 'abc' }.item, d:{ item: __sveltets_1_unwrapArr(items) }, e:$item, f:$item}}, getters: {}, events: {} }} +return { props: {}, slots: {'default': {a:__sveltets_1_unwrapArr(items), b:{ item:__sveltets_1_unwrapArr(items) }, c:{ item: 'abc' }.item, d:{ item: __sveltets_1_unwrapArr(items) }, e:$item, f:$item, ...g, ...__sveltets_1_unwrapArr(items)}}, getters: {}, events: {} }} export default class Input__SvelteComponent_ extends __sveltets_1_createSvelte2TsxComponent(__sveltets_1_partial(__sveltets_1_with_any_event(render()))) { } \ No newline at end of file diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/input.svelte index 684b9027f..5bd80cfb9 100644 --- a/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/input.svelte +++ b/packages/svelte2tsx/test/svelte2tsx/samples/component-slot-object-key/input.svelte @@ -1,3 +1,3 @@ {#each items as item} - Hello + Hello {/each}