diff --git a/site/content/blog/2020-12-01-whats-new-in-svelte-december-2020.md b/site/content/blog/2020-12-01-whats-new-in-svelte-december-2020.md index 5edaf31311..2bcb9f105c 100644 --- a/site/content/blog/2020-12-01-whats-new-in-svelte-december-2020.md +++ b/site/content/blog/2020-12-01-whats-new-in-svelte-december-2020.md @@ -11,7 +11,7 @@ It's the last "What's new in Svelte" of the year and there's lots to celebrate! 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: `` (**3.30.0**) 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)) -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)) +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)) 4. Transitions within `{:else}` blocks should now complete successfully (**3.29.5**, [Example](https://svelte.dev/repl/49cef205e5da459594ef2eafcbd41593?version=3.29.5)) 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**) 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) diff --git a/src/runtime/index.ts b/src/runtime/index.ts index f1154b092f..b3451ed5cb 100644 --- a/src/runtime/index.ts +++ b/src/runtime/index.ts @@ -10,5 +10,6 @@ export { hasContext, tick, createEventDispatcher, - SvelteComponentDev as SvelteComponent + SvelteComponentDev as SvelteComponent, + SvelteComponentTyped } from 'svelte/internal'; diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index d107dd3997..459a78031a 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -212,19 +212,16 @@ if (typeof HTMLElement === 'function') { }; } -export class SvelteComponent< - Props extends Record = any, - Events extends Record = any -> { +export class SvelteComponent { $$: T$$; - $$set?: ($$props: Partial) => void; + $$set?: ($$props: any) => void; $destroy() { destroy_component(this, 1); this.$destroy = noop; } - $on>(type: K, callback: (e: Events[K]) => void) { + $on(type, callback) { const callbacks = (this.$$.callbacks[type] || (this.$$.callbacks[type] = [])); callbacks.push(callback); @@ -234,7 +231,7 @@ export class SvelteComponent< }; } - $set($$props: Partial) { + $set($$props) { if (this.$$set && !is_empty($$props)) { this.$$.skip_bound = true; this.$$set($$props); diff --git a/src/runtime/internal/dev.ts b/src/runtime/internal/dev.ts index e93523572f..4d79536411 100644 --- a/src/runtime/internal/dev.ts +++ b/src/runtime/internal/dev.ts @@ -97,22 +97,55 @@ export function validate_slots(name, slot, keys) { } } -export interface SvelteComponentDev< - Props extends Record = any, - Events extends Record = any, - Slots extends Record = any -> { - $set(props?: Partial): void; - $on>(type: K, callback: (e: Events[K]) => void): () => void; +type Props = Record; +export interface SvelteComponentDev { + $set(props?: Props): void; + $on(event: string, callback: (event: any) => void): () => void; $destroy(): void; [accessor: string]: any; } -export class SvelteComponentDev< +export class SvelteComponentDev extends SvelteComponent { + /** + * @private + * For type checking capabilities only. + * Does not exist at runtime. + * ### DO NOT USE! + */ + $$prop_def: Props; + + constructor(options: { + target: Element; + anchor?: Element; + props?: Props; + hydrate?: boolean; + intro?: boolean; + $$inline?: boolean; + }) { + if (!options || (!options.target && !options.$$inline)) { + throw new Error("'target' is a required option"); + } + + super(); + } + + $destroy() { + super.$destroy(); + this.$destroy = () => { + console.warn('Component was already destroyed'); // eslint-disable-line no-console + }; + } + + $capture_state() {} + + $inject_state() {} +} + +export declare class SvelteComponentTyped< Props extends Record = any, Events extends Record = any, Slots extends Record = any -> extends SvelteComponent { +> extends SvelteComponentDev { /** * @private * For type checking capabilities only. @@ -142,24 +175,12 @@ export class SvelteComponentDev< hydrate?: boolean; intro?: boolean; $$inline?: boolean; - }) { - if (!options || (!options.target && !options.$$inline)) { - throw new Error("'target' is a required option"); - } - - super(); - } + }) - $destroy() { - super.$destroy(); - this.$destroy = () => { - console.warn('Component was already destroyed'); // eslint-disable-line no-console - }; - } - - $capture_state() {} - - $inject_state() {} + $set(props?: Partial): void; + $on>(type: K, callback: (e: Events[K]) => void): () => void; + $destroy(): void; + [accessor: string]: any; } export function loop_guard(timeout) {