Skip to content

Commit 79214cc

Browse files
authored
Revert typed SvelteComponent, add SvelteComponentTyped instead (#5738)
1 parent 307b86b commit 79214cc

File tree

4 files changed

+96
-30
lines changed

4 files changed

+96
-30
lines changed

site/content/blog/2020-12-01-whats-new-in-svelte-december-2020.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ It's the last "What's new in Svelte" of the year and there's lots to celebrate!
1111

1212
1. `$$props`, `$$restProps`, and `$$slots` are all now supported in custom web components (**3.29.5**, [Example](https://svelte.dev/repl/ad8e6f39cd20403dacd1be84d71e498d?version=3.29.5)) and `slot` components now support spread props: `<slot {...foo} />` (**3.30.0**)
1313
2. A new `hasContext` lifecycle function makes it easy to check whether a `key` has been set in the context of a parent component (**3.30.0** & **3.30.1**, [Docs](https://svelte.dev/docs#hasContext))
14-
3. `SvelteComponent` is now typed which makes it easier to add typed classes that extend base Svelte Components. Component library and framework authors rejoice! An example: `export class YourComponent extends SvelteComponent<{aProp: boolean}, {click: MouseEvent}, {default: {aSlot: string}}> {}` (**3.30.0**, [RFC](https://github.com/sveltejs/rfcs/pull/37))
14+
3. There is now a new `SvelteComponentTyped` class which makes it easier to add strongly typed components that extend base Svelte components. Component library and framework authors rejoice! An example: `export class YourComponent extends SvelteComponentTyped<{aProp: boolean}, {click: MouseEvent}, {default: {aSlot: string}}> {}` (**3.30.0**, [RFC](https://github.com/sveltejs/rfcs/pull/37))
1515
4. Transitions within `{:else}` blocks should now complete successfully (**3.29.5**, [Example](https://svelte.dev/repl/49cef205e5da459594ef2eafcbd41593?version=3.29.5))
1616
5. Svelte now includes an export map, which explicitly states which files can be imported from its npm package (**3.29.5** with some fixes in **3.29.6**, **3.29.7** and **3.30.0**)
1717
6. `rollup-plugin-svelte` had a new [7.0.0 release](https://github.com/sveltejs/rollup-plugin-svelte/blob/master/CHANGELOG.md). The biggest change is that the `css` option was removed. Users who were using that option should add another plugin like `rollup-plugin-css-only` as demonstrated [in the template](https://github.com/sveltejs/template/blob/5b1135c286f7a649daa99825a077586655051649/rollup.config.js#L48)

src/runtime/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export {
1010
hasContext,
1111
tick,
1212
createEventDispatcher,
13-
SvelteComponentDev as SvelteComponent
13+
SvelteComponentDev as SvelteComponent,
14+
SvelteComponentTyped
1415
} from 'svelte/internal';

src/runtime/internal/Component.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,19 +212,19 @@ if (typeof HTMLElement === 'function') {
212212
};
213213
}
214214

215-
export class SvelteComponent<
216-
Props extends Record<string, any> = any,
217-
Events extends Record<string, any> = any
218-
> {
215+
/**
216+
* Base class for Svelte components. Used when dev=false.
217+
*/
218+
export class SvelteComponent {
219219
$$: T$$;
220-
$$set?: ($$props: Partial<Props>) => void;
220+
$$set?: ($$props: any) => void;
221221

222222
$destroy() {
223223
destroy_component(this, 1);
224224
this.$destroy = noop;
225225
}
226226

227-
$on<K extends Extract<keyof Events, string>>(type: K, callback: (e: Events[K]) => void) {
227+
$on(type, callback) {
228228
const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = []));
229229
callbacks.push(callback);
230230

@@ -234,7 +234,7 @@ export class SvelteComponent<
234234
};
235235
}
236236

237-
$set($$props: Partial<Props>) {
237+
$set($$props) {
238238
if (this.$$set && !is_empty($$props)) {
239239
this.$$.skip_bound = true;
240240
this.$$set($$props);

src/runtime/internal/dev.ts

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,57 @@ export function validate_slots(name, slot, keys) {
9797
}
9898
}
9999

100-
export interface SvelteComponentDev<
100+
type Props = Record<string, any>;
101+
export interface SvelteComponentDev {
102+
$set(props?: Props): void;
103+
$on(event: string, callback: (event: any) => void): () => void;
104+
$destroy(): void;
105+
[accessor: string]: any;
106+
}
107+
/**
108+
* Base class for Svelte components with some minor dev-enhancements. Used when dev=true.
109+
*/
110+
export class SvelteComponentDev extends SvelteComponent {
111+
/**
112+
* @private
113+
* For type checking capabilities only.
114+
* Does not exist at runtime.
115+
* ### DO NOT USE!
116+
*/
117+
$$prop_def: Props;
118+
119+
constructor(options: {
120+
target: Element;
121+
anchor?: Element;
122+
props?: Props;
123+
hydrate?: boolean;
124+
intro?: boolean;
125+
$$inline?: boolean;
126+
}) {
127+
if (!options || (!options.target && !options.$$inline)) {
128+
throw new Error("'target' is a required option");
129+
}
130+
131+
super();
132+
}
133+
134+
$destroy() {
135+
super.$destroy();
136+
this.$destroy = () => {
137+
console.warn('Component was already destroyed'); // eslint-disable-line no-console
138+
};
139+
}
140+
141+
$capture_state() {}
142+
143+
$inject_state() {}
144+
}
145+
146+
// TODO https://github.com/microsoft/TypeScript/issues/41770 is the reason
147+
// why we have to split out SvelteComponentTyped to not break existing usage of SvelteComponent.
148+
// Try to find a better way for Svelte 4.0.
149+
150+
export interface SvelteComponentTyped<
101151
Props extends Record<string, any> = any,
102152
Events extends Record<string, any> = any,
103153
Slots extends Record<string, any> = any
@@ -107,12 +157,42 @@ export interface SvelteComponentDev<
107157
$destroy(): void;
108158
[accessor: string]: any;
109159
}
110-
111-
export class SvelteComponentDev<
160+
/**
161+
* Base class to create strongly typed Svelte components.
162+
* This only exists for typing purposes and should be used in `.d.ts` files.
163+
*
164+
* ### Example:
165+
*
166+
* You have component library on npm called `component-library`, from which
167+
* you export a component called `MyComponent`. For Svelte+TypeScript users,
168+
* you want to provide typings. Therefore you create a `index.d.ts`:
169+
* ```ts
170+
* import { SvelteComponentTyped } from "svelte";
171+
* export class MyComponent extends SvelteComponentTyped<{foo: string}> {}
172+
* ```
173+
* Typing this makes it possible for IDEs like VS Code with the Svelte extension
174+
* to provide intellisense and to use the component like this in a Svelte file
175+
* with TypeScript:
176+
* ```svelte
177+
* <script lang="ts">
178+
* import { MyComponent } from "component-library";
179+
* </script>
180+
* <MyComponent foo={'bar'} />
181+
* ```
182+
*
183+
* #### Why not make this part of `SvelteComponent(Dev)`?
184+
* Because
185+
* ```ts
186+
* class ASubclassOfSvelteComponent extends SvelteComponent<{foo: string}> {}
187+
* const component: typeof SvelteComponent = ASubclassOfSvelteComponent;
188+
* ```
189+
* will throw a type error, so we need to seperate the more strictly typed class.
190+
*/
191+
export class SvelteComponentTyped<
112192
Props extends Record<string, any> = any,
113193
Events extends Record<string, any> = any,
114194
Slots extends Record<string, any> = any
115-
> extends SvelteComponent<Props, Events> {
195+
> extends SvelteComponentDev {
116196
/**
117197
* @private
118198
* For type checking capabilities only.
@@ -142,24 +222,9 @@ export class SvelteComponentDev<
142222
hydrate?: boolean;
143223
intro?: boolean;
144224
$$inline?: boolean;
145-
}) {
146-
if (!options || (!options.target && !options.$$inline)) {
147-
throw new Error("'target' is a required option");
148-
}
149-
150-
super();
225+
}) {
226+
super(options);
151227
}
152-
153-
$destroy() {
154-
super.$destroy();
155-
this.$destroy = () => {
156-
console.warn('Component was already destroyed'); // eslint-disable-line no-console
157-
};
158-
}
159-
160-
$capture_state() {}
161-
162-
$inject_state() {}
163228
}
164229

165230
export function loop_guard(timeout) {

0 commit comments

Comments
 (0)