diff --git a/src/compiler/compile/render_dom/invalidate.ts b/src/compiler/compile/render_dom/invalidate.ts index 7eeb34a89400..31df2cbe3b5b 100644 --- a/src/compiler/compile/render_dom/invalidate.ts +++ b/src/compiler/compile/render_dom/invalidate.ts @@ -50,6 +50,7 @@ export function invalidate(renderer: Renderer, scope: Scope, node: Node, names: const extra_args = tail.map(variable => get_invalidated(variable)).filter(Boolean); if (is_store_value) { + // TODO: check why there are 4 parameters, but `set_store_value` only expects 3 return x`@set_store_value(${head.name.slice(1)}, ${node}, ${head.name}, ${extra_args})`; } diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 8868e38ee29f..0111c2a94a18 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -1,13 +1,16 @@ -import { Readable } from 'svelte/store'; +import { Readable, Subscriber, Invalidator, Writable } from 'svelte/store'; +import { SvelteComponent } from '..'; -export function noop() {} +export function noop() { } -export const identity = x => x; +export function identity(x: T): T { + return x; +} -export function assign(tar: T, src: S): T & S { +export function assign(target: T, source: S): T & S { // @ts-ignore - for (const k in src) tar[k] = src[k]; - return tar as T & S; + for (const k in source) target[k] = source[k]; + return target as T & S; } export function is_promise(value: any): value is PromiseLike { @@ -20,15 +23,17 @@ export function add_location(element, file, line, column, char) { }; } -export function run(fn) { - return fn(); +export function blank_object(): {} { + return Object.create(null); } -export function blank_object() { - return Object.create(null); +type FunctionWithoutArguments = () => unknown + +export function run(fn: FunctionWithoutArguments) { + return fn(); } -export function run_all(fns: Function[]) { +export function run_all(fns: FunctionWithoutArguments[]) { fns.forEach(run); } @@ -36,13 +41,9 @@ export function is_function(thing: any): thing is Function { return typeof thing === 'function'; } -export function safe_not_equal(a, b) { - return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); -} - -let src_url_equal_anchor; +let src_url_equal_anchor: HTMLAnchorElement; -export function src_url_equal(element_src, url) { +export function src_url_equal(element_src: string, url: string) { if (!src_url_equal_anchor) { src_url_equal_anchor = document.createElement('a'); } @@ -50,52 +51,55 @@ export function src_url_equal(element_src, url) { return element_src === src_url_equal_anchor.href; } -export function not_equal(a, b) { +export function safe_not_equal(a: unknown, b: unknown) { + return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} + +export function not_equal(a: unknown, b: unknown) { return a != a ? b == b : a !== b; } -export function is_empty(obj) { +export function is_empty(obj: Record) { return Object.keys(obj).length === 0; } -export function validate_store(store, name) { +export function validate_store>(store: S, name: string) { if (store != null && typeof store.subscribe !== 'function') { throw new Error(`'${name}' is not a store with a 'subscribe' method`); } } -export function subscribe(store, ...callbacks) { +export function subscribe>(store: S, run: Subscriber, invalidate?: Invalidator) { if (store == null) { return noop; } - const unsub = store.subscribe(...callbacks); - return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; + return store.subscribe(run, invalidate); } -export function get_store_value(store: Readable): T { - let value; - subscribe(store, _ => value = _)(); +export function get_store_value>(store: S): T { + let value: T; + subscribe(store, v => value = v)(); return value; } -export function component_subscribe(component, store, callback) { +export function component_subscribe>(component: SvelteComponent, store: S, callback: Subscriber) { component.$$.on_destroy.push(subscribe(store, callback)); } -export function create_slot(definition, ctx, $$scope, fn) { +export function create_slot(definition, ctx, $$scope, fn: Function) { if (definition) { const slot_ctx = get_slot_context(definition, ctx, $$scope, fn); return definition[0](slot_ctx); } } -function get_slot_context(definition, ctx, $$scope, fn) { +function get_slot_context(definition, ctx, $$scope, fn: Function) { return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx; } -export function get_slot_changes(definition, $$scope, dirty, fn) { +export function get_slot_changes(definition, $$scope, dirty, fn: Function) { if (definition[2] && fn) { const lets = definition[2](fn(dirty)); @@ -164,25 +168,27 @@ export function compute_slots(slots) { return result; } -export function once(fn) { +export function once(fn: Function) { let ran = false; - return function(this: any, ...args) { + return function (this: any, ...args: unknown[]) { if (ran) return; ran = true; fn.call(this, ...args); }; } -export function null_to_empty(value) { - return value == null ? '' : value; +export function null_to_empty(value: T): T extends null | undefined ? '' : T { + return (value == null ? '' : value) as T extends null | undefined ? '' : T; } -export function set_store_value(store, ret, value) { +export function set_store_value>(store: S, ret: Node, value: T) { store.set(value); return ret; } -export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); +export function has_prop(obj: X, prop: Y): obj is X & Record { + return Object.prototype.hasOwnProperty.call(obj, prop); +} export function action_destroyer(action_result) { return action_result && is_function(action_result.destroy) ? action_result.destroy : noop; diff --git a/src/runtime/store/index.ts b/src/runtime/store/index.ts index e947fa074028..a3132342fa94 100644 --- a/src/runtime/store/index.ts +++ b/src/runtime/store/index.ts @@ -10,7 +10,7 @@ export type Unsubscriber = () => void; export type Updater = (value: T) => T; /** Cleanup logic callback. */ -type Invalidator = (value?: T) => void; +export type Invalidator = (value?: T) => void; /** Start and stop notification callbacks. */ export type StartStopNotifier = (set: Subscriber) => Unsubscriber | void;