Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/few-tips-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': minor
---

improve types for props when using Client-side component API
12 changes: 6 additions & 6 deletions packages/svelte/src/runtime/internal/dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,9 +292,9 @@ export function construct_svelte_component_dev(component, props) {
* </script>
* <MyComponent foo={'bar'} />
* ```
* @template {Record<string, any>} [Props=any]
* @template {Record<string, any>} [Events=any]
* @template {Record<string, any>} [Slots=any]
* @template {Record<string, any> | never} [Props=Record<string, any>]
* @template {Record<string, any>} [Events=Record<string, any>]
* @template {Record<string, any>} [Slots=Record<string, any>]
* @extends {SvelteComponent<Props, Events>}
*/
export class SvelteComponentDev extends SvelteComponent {
Expand Down Expand Up @@ -346,9 +346,9 @@ export class SvelteComponentDev extends SvelteComponent {
$inject_state() {}
}
/**
* @template {Record<string, any>} [Props=any]
* @template {Record<string, any>} [Events=any]
* @template {Record<string, any>} [Slots=any]
* @template {Record<string, any> | never} [Props=Record<string, any>]
* @template {Record<string, any>} [Events=Record<string, any>]
* @template {Record<string, any>} [Slots=Record<string, any>]
* @deprecated Use `SvelteComponent` instead. See PR for more information: https://github.com/sveltejs/svelte/pull/8512
* @extends {SvelteComponentDev<Props, Events, Slots>}
*/
Expand Down
25 changes: 21 additions & 4 deletions packages/svelte/src/runtime/internal/public.d.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,35 @@
import { SvelteComponent } from './Component.js';
import { SvelteComponentDev } from './dev.js';

export interface ComponentConstructorOptions<
Props extends Record<string, any> = Record<string, any>
> {
interface ComponentConstructorOptionsWithoutProps {
target: Element | Document | ShadowRoot;
anchor?: Element;
props?: Props;
context?: Map<any, any>;
hydrate?: boolean;
intro?: boolean;
$$inline?: boolean;
}

interface ComponentConstructorOptionsWithProps<
Props extends Record<string, any> = Record<string, any>
> extends ComponentConstructorOptionsWithoutProps {
props: Props;
}

interface ComponentConstructorOptionsWithOptionalProps<
Props extends Record<string, any> = Record<string, any>
> extends ComponentConstructorOptionsWithoutProps {
props?: Props;
}

export type ComponentConstructorOptions<Props extends Record<string, any> | never = never> = [
Props
] extends [never]
? ComponentConstructorOptionsWithoutProps
: Record<string, any> extends Props
? ComponentConstructorOptionsWithOptionalProps
: ComponentConstructorOptionsWithProps<Props>;

/**
* Convenience type to get the events the given component expects. Example:
* ```html
Expand Down
59 changes: 59 additions & 0 deletions packages/svelte/test/types/component-constructor-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ComponentConstructorOptions } from '$runtime/internal/public.js';

type NoProps = ComponentConstructorOptions;

const n1: NoProps = {
target: document.body
};

const n2: NoProps = {
target: document.body,
// @ts-expect-error does not accept props
props: {}
};

const n3: NoProps = {
target: document.body,
// @ts-expect-error does not accept any props
props: {
img: ''
}
};

type Props = ComponentConstructorOptions<{ img: string }>;

// @ts-expect-error
const p1: Props = {
target: document.body
};

const p2: Props = {
target: document.body,
// @ts-expect-error required prop is missing
props: {}
};

const p3: Props = {
target: document.body,
props: {
img: ''
}
};

type OptionalProps = ComponentConstructorOptions<{ img?: string }>;

const o1: OptionalProps = {
target: document.body
};

const o2: OptionalProps = {
target: document.body,
props: {}
};

const o3: OptionalProps = {
target: document.body,
props: {
img: ''
}
};