From b5886189ba2c268eda538db07ec37dc59fd67239 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 22 Oct 2019 11:26:48 -0400 Subject: [PATCH] types: massive refactor --- packages/reactivity/src/baseHandlers.ts | 31 ++-- packages/reactivity/src/collectionHandlers.ts | 129 +++++++++------ packages/reactivity/src/computed.ts | 2 +- packages/reactivity/src/effect.ts | 60 ++++--- packages/reactivity/src/reactive.ts | 8 +- packages/reactivity/src/ref.ts | 39 +++-- .../runtime-core/src/apiCreateComponent.ts | 2 +- packages/runtime-core/src/apiInject.ts | 5 +- packages/runtime-core/src/apiLifecycle.ts | 2 +- packages/runtime-core/src/apiOptions.ts | 24 ++- packages/runtime-core/src/apiWatch.ts | 28 ++-- packages/runtime-core/src/component.ts | 6 +- packages/runtime-core/src/componentProps.ts | 38 ++--- packages/runtime-core/src/componentProxy.ts | 18 ++- packages/runtime-core/src/createRenderer.ts | 147 ++++++++++-------- packages/runtime-core/src/directives.ts | 2 +- packages/runtime-core/src/errorHandling.ts | 6 +- .../runtime-core/src/helpers/renderList.ts | 8 +- .../runtime-core/src/helpers/renderSlot.ts | 3 +- packages/runtime-core/src/helpers/toString.ts | 6 +- packages/runtime-dom/src/modules/events.ts | 2 +- 21 files changed, 308 insertions(+), 258 deletions(-) diff --git a/packages/reactivity/src/baseHandlers.ts b/packages/reactivity/src/baseHandlers.ts index 0043af73..f75c5b74 100644 --- a/packages/reactivity/src/baseHandlers.ts +++ b/packages/reactivity/src/baseHandlers.ts @@ -12,7 +12,7 @@ const builtInSymbols = new Set( ) function createGetter(isReadonly: boolean) { - return function get(target: any, key: string | symbol, receiver: any) { + return function get(target: object, key: string | symbol, receiver: object) { const res = Reflect.get(target, key, receiver) if (isSymbol(key) && builtInSymbols.has(key)) { return res @@ -32,13 +32,13 @@ function createGetter(isReadonly: boolean) { } function set( - target: any, + target: object, key: string | symbol, - value: any, - receiver: any + value: unknown, + receiver: object ): boolean { value = toRaw(value) - const oldValue = target[key] + const oldValue = (target as any)[key] if (isRef(oldValue) && !isRef(value)) { oldValue.value = value return true @@ -66,9 +66,9 @@ function set( return result } -function deleteProperty(target: any, key: string | symbol): boolean { +function deleteProperty(target: object, key: string | symbol): boolean { const hadKey = hasOwn(target, key) - const oldValue = target[key] + const oldValue = (target as any)[key] const result = Reflect.deleteProperty(target, key) if (result && hadKey) { /* istanbul ignore else */ @@ -81,18 +81,18 @@ function deleteProperty(target: any, key: string | symbol): boolean { return result } -function has(target: any, key: string | symbol): boolean { +function has(target: object, key: string | symbol): boolean { const result = Reflect.has(target, key) track(target, OperationTypes.HAS, key) return result } -function ownKeys(target: any): (string | number | symbol)[] { +function ownKeys(target: object): (string | number | symbol)[] { track(target, OperationTypes.ITERATE) return Reflect.ownKeys(target) } -export const mutableHandlers: ProxyHandler = { +export const mutableHandlers: ProxyHandler = { get: createGetter(false), set, deleteProperty, @@ -100,10 +100,15 @@ export const mutableHandlers: ProxyHandler = { ownKeys } -export const readonlyHandlers: ProxyHandler = { +export const readonlyHandlers: ProxyHandler = { get: createGetter(true), - set(target: any, key: string | symbol, value: any, receiver: any): boolean { + set( + target: object, + key: string | symbol, + value: unknown, + receiver: object + ): boolean { if (LOCKED) { if (__DEV__) { console.warn( @@ -117,7 +122,7 @@ export const readonlyHandlers: ProxyHandler = { } }, - deleteProperty(target: any, key: string | symbol): boolean { + deleteProperty(target: object, key: string | symbol): boolean { if (LOCKED) { if (__DEV__) { console.warn( diff --git a/packages/reactivity/src/collectionHandlers.ts b/packages/reactivity/src/collectionHandlers.ts index dfd62136..fc721d76 100644 --- a/packages/reactivity/src/collectionHandlers.ts +++ b/packages/reactivity/src/collectionHandlers.ts @@ -4,43 +4,56 @@ import { OperationTypes } from './operations' import { LOCKED } from './lock' import { isObject, capitalize, hasOwn } from '@vue/shared' -const toReactive = (value: any) => (isObject(value) ? reactive(value) : value) -const toReadonly = (value: any) => (isObject(value) ? readonly(value) : value) +export type CollectionTypes = IterableCollections | WeakCollections -function get(target: any, key: any, wrap: (t: any) => any): any { +type IterableCollections = Map | Set +type WeakCollections = WeakMap | WeakSet +type MapTypes = Map | WeakMap +type SetTypes = Set | WeakSet + +const toReactive = (value: T): T => + isObject(value) ? reactive(value) : value + +const toReadonly = (value: T): T => + isObject(value) ? readonly(value) : value + +const getProto = (v: T): any => + Reflect.getPrototypeOf(v) + +function get( + target: MapTypes, + key: unknown, + wrap: typeof toReactive | typeof toReadonly +) { target = toRaw(target) key = toRaw(key) - const proto: any = Reflect.getPrototypeOf(target) track(target, OperationTypes.GET, key) - const res = proto.get.call(target, key) - return wrap(res) + return wrap(getProto(target).get.call(target, key)) } -function has(this: any, key: any): boolean { +function has(this: CollectionTypes, key: unknown): boolean { const target = toRaw(this) key = toRaw(key) - const proto: any = Reflect.getPrototypeOf(target) track(target, OperationTypes.HAS, key) - return proto.has.call(target, key) + return getProto(target).has.call(target, key) } -function size(target: any) { +function size(target: IterableCollections) { target = toRaw(target) - const proto = Reflect.getPrototypeOf(target) track(target, OperationTypes.ITERATE) - return Reflect.get(proto, 'size', target) + return Reflect.get(getProto(target), 'size', target) } -function add(this: any, value: any) { +function add(this: SetTypes, value: unknown) { value = toRaw(value) const target = toRaw(this) - const proto: any = Reflect.getPrototypeOf(this) + const proto = getProto(target) const hadKey = proto.has.call(target, value) const result = proto.add.call(target, value) if (!hadKey) { /* istanbul ignore else */ if (__DEV__) { - trigger(target, OperationTypes.ADD, value, { value }) + trigger(target, OperationTypes.ADD, value, { newValue: value }) } else { trigger(target, OperationTypes.ADD, value) } @@ -48,10 +61,10 @@ function add(this: any, value: any) { return result } -function set(this: any, key: any, value: any) { +function set(this: MapTypes, key: unknown, value: unknown) { value = toRaw(value) const target = toRaw(this) - const proto: any = Reflect.getPrototypeOf(this) + const proto = getProto(target) const hadKey = proto.has.call(target, key) const oldValue = proto.get.call(target, key) const result = proto.set.call(target, key, value) @@ -75,9 +88,9 @@ function set(this: any, key: any, value: any) { return result } -function deleteEntry(this: any, key: any) { +function deleteEntry(this: CollectionTypes, key: unknown) { const target = toRaw(this) - const proto: any = Reflect.getPrototypeOf(this) + const proto = getProto(target) const hadKey = proto.has.call(target, key) const oldValue = proto.get ? proto.get.call(target, key) : undefined // forward the operation before queueing reactions @@ -93,13 +106,16 @@ function deleteEntry(this: any, key: any) { return result } -function clear(this: any) { +function clear(this: IterableCollections) { const target = toRaw(this) - const proto: any = Reflect.getPrototypeOf(this) const hadItems = target.size !== 0 - const oldTarget = target instanceof Map ? new Map(target) : new Set(target) + const oldTarget = __DEV__ + ? target instanceof Map + ? new Map(target) + : new Set(target) + : undefined // forward the operation before queueing reactions - const result = proto.clear.call(target) + const result = getProto(target).clear.call(target) if (hadItems) { /* istanbul ignore else */ if (__DEV__) { @@ -112,30 +128,32 @@ function clear(this: any) { } function createForEach(isReadonly: boolean) { - return function forEach(this: any, callback: Function, thisArg?: any) { + return function forEach( + this: IterableCollections, + callback: Function, + thisArg?: unknown + ) { const observed = this const target = toRaw(observed) - const proto: any = Reflect.getPrototypeOf(target) const wrap = isReadonly ? toReadonly : toReactive track(target, OperationTypes.ITERATE) // important: create sure the callback is // 1. invoked with the reactive map as `this` and 3rd arg // 2. the value received should be a corresponding reactive/readonly. - function wrappedCallback(value: any, key: any) { + function wrappedCallback(value: unknown, key: unknown) { return callback.call(observed, wrap(value), wrap(key), observed) } - return proto.forEach.call(target, wrappedCallback, thisArg) + return getProto(target).forEach.call(target, wrappedCallback, thisArg) } } function createIterableMethod(method: string | symbol, isReadonly: boolean) { - return function(this: any, ...args: any[]) { + return function(this: IterableCollections, ...args: unknown[]) { const target = toRaw(this) - const proto: any = Reflect.getPrototypeOf(target) const isPair = method === 'entries' || (method === Symbol.iterator && target instanceof Map) - const innerIterator = proto[method].apply(target, args) + const innerIterator = getProto(target)[method].apply(target, args) const wrap = isReadonly ? toReadonly : toReactive track(target, OperationTypes.ITERATE) // return a wrapped iterator which returns observed versions of the @@ -163,7 +181,7 @@ function createReadonlyMethod( method: Function, type: OperationTypes ): Function { - return function(this: any, ...args: any[]) { + return function(this: CollectionTypes, ...args: unknown[]) { if (LOCKED) { if (__DEV__) { const key = args[0] ? `on key "${args[0]}" ` : `` @@ -179,11 +197,11 @@ function createReadonlyMethod( } } -const mutableInstrumentations: any = { - get(key: any) { +const mutableInstrumentations: Record = { + get(this: MapTypes, key: unknown) { return get(this, key, toReactive) }, - get size() { + get size(this: IterableCollections) { return size(this) }, has, @@ -194,11 +212,11 @@ const mutableInstrumentations: any = { forEach: createForEach(false) } -const readonlyInstrumentations: any = { - get(key: any) { +const readonlyInstrumentations: Record = { + get(this: MapTypes, key: unknown) { return get(this, key, toReadonly) }, - get size() { + get size(this: IterableCollections) { return size(this) }, has, @@ -211,26 +229,37 @@ const readonlyInstrumentations: any = { const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator] iteratorMethods.forEach(method => { - mutableInstrumentations[method] = createIterableMethod(method, false) - readonlyInstrumentations[method] = createIterableMethod(method, true) + mutableInstrumentations[method as string] = createIterableMethod( + method, + false + ) + readonlyInstrumentations[method as string] = createIterableMethod( + method, + true + ) }) -function createInstrumentationGetter(instrumentations: any) { - return function getInstrumented( - target: any, +function createInstrumentationGetter( + instrumentations: Record +) { + return ( + target: CollectionTypes, key: string | symbol, - receiver: any - ) { - target = - hasOwn(instrumentations, key) && key in target ? instrumentations : target - return Reflect.get(target, key, receiver) - } + receiver: CollectionTypes + ) => + Reflect.get( + hasOwn(instrumentations, key) && key in target + ? instrumentations + : target, + key, + receiver + ) } -export const mutableCollectionHandlers: ProxyHandler = { +export const mutableCollectionHandlers: ProxyHandler = { get: createInstrumentationGetter(mutableInstrumentations) } -export const readonlyCollectionHandlers: ProxyHandler = { +export const readonlyCollectionHandlers: ProxyHandler = { get: createInstrumentationGetter(readonlyInstrumentations) } diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index 162eb767..30ae8180 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -24,7 +24,7 @@ export function computed( ): WritableComputedRef export function computed( getterOrOptions: ComputedGetter | WritableComputedOptions -): any { +) { const isReadonly = isFunction(getterOrOptions) const getter = isReadonly ? (getterOrOptions as ComputedGetter) diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 422d08e0..1a7a761e 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -2,11 +2,9 @@ import { OperationTypes } from './operations' import { Dep, targetMap } from './reactive' import { EMPTY_OBJ, extend } from '@vue/shared' -export const effectSymbol = Symbol(__DEV__ ? 'effect' : void 0) - export interface ReactiveEffect { (): T - [effectSymbol]: true + _isEffect: true active: boolean raw: () => T deps: Array @@ -26,11 +24,17 @@ export interface ReactiveEffectOptions { onStop?: () => void } -export interface DebuggerEvent { +type DebuggerEvent = { effect: ReactiveEffect - target: any + target: object type: OperationTypes - key: string | symbol | undefined + key: any +} & DebuggerEventExtraInfo + +export interface DebuggerEventExtraInfo { + newValue?: any + oldValue?: any + oldTarget?: Map | Set } export const effectStack: ReactiveEffect[] = [] @@ -38,7 +42,7 @@ export const effectStack: ReactiveEffect[] = [] export const ITERATE_KEY = Symbol('iterate') export function isEffect(fn: any): fn is ReactiveEffect { - return fn != null && fn[effectSymbol] === true + return fn != null && fn._isEffect === true } export function effect( @@ -69,10 +73,10 @@ function createReactiveEffect( fn: () => T, options: ReactiveEffectOptions ): ReactiveEffect { - const effect = function reactiveEffect(...args: any[]): any { + const effect = function reactiveEffect(...args: unknown[]): unknown { return run(effect, fn, args) } as ReactiveEffect - effect[effectSymbol] = true + effect._isEffect = true effect.active = true effect.raw = fn effect.scheduler = options.scheduler @@ -84,7 +88,7 @@ function createReactiveEffect( return effect } -function run(effect: ReactiveEffect, fn: Function, args: any[]): any { +function run(effect: ReactiveEffect, fn: Function, args: unknown[]): unknown { if (!effect.active) { return fn(...args) } @@ -119,11 +123,7 @@ export function resumeTracking() { shouldTrack = true } -export function track( - target: any, - type: OperationTypes, - key?: string | symbol -) { +export function track(target: object, type: OperationTypes, key?: unknown) { if (!shouldTrack || effectStack.length === 0) { return } @@ -154,10 +154,10 @@ export function track( } export function trigger( - target: any, + target: object, type: OperationTypes, - key?: string | symbol, - extraInfo?: any + key?: unknown, + extraInfo?: DebuggerEventExtraInfo ) { const depsMap = targetMap.get(target) if (depsMap === void 0) { @@ -209,23 +209,19 @@ function addRunners( function scheduleRun( effect: ReactiveEffect, - target: any, + target: object, type: OperationTypes, - key: string | symbol | undefined, - extraInfo: any + key: unknown, + extraInfo?: DebuggerEventExtraInfo ) { if (__DEV__ && effect.onTrigger) { - effect.onTrigger( - extend( - { - effect, - target, - key, - type - }, - extraInfo - ) - ) + const event: DebuggerEvent = { + effect, + target, + key, + type + } + effect.onTrigger(extraInfo ? extend(event, extraInfo) : event) } if (effect.scheduler !== void 0) { effect.scheduler(effect) diff --git a/packages/reactivity/src/reactive.ts b/packages/reactivity/src/reactive.ts index 2f21add9..eec2eab1 100644 --- a/packages/reactivity/src/reactive.ts +++ b/packages/reactivity/src/reactive.ts @@ -13,7 +13,7 @@ import { makeMap } from '@vue/shared' // which maintains a Set of subscribers, but we simply store them as // raw Sets to reduce memory overhead. export type Dep = Set -export type KeyToDepMap = Map +export type KeyToDepMap = Map export const targetMap = new WeakMap() // WeakMaps that store {raw <-> observed} pairs. @@ -83,7 +83,7 @@ export function readonly( } function createReactiveObject( - target: any, + target: unknown, toProxy: WeakMap, toRaw: WeakMap, baseHandlers: ProxyHandler, @@ -120,11 +120,11 @@ function createReactiveObject( return observed } -export function isReactive(value: any): boolean { +export function isReactive(value: unknown): boolean { return reactiveToRaw.has(value) || readonlyToRaw.has(value) } -export function isReadonly(value: any): boolean { +export function isReadonly(value: unknown): boolean { return readonlyToRaw.has(value) } diff --git a/packages/reactivity/src/ref.ts b/packages/reactivity/src/ref.ts index 795be28b..58c9c639 100644 --- a/packages/reactivity/src/ref.ts +++ b/packages/reactivity/src/ref.ts @@ -3,37 +3,39 @@ import { OperationTypes } from './operations' import { isObject } from '@vue/shared' import { reactive } from './reactive' import { ComputedRef } from './computed' +import { CollectionTypes } from './collectionHandlers' export interface Ref { _isRef: true value: UnwrapRef } -const convert = (val: any): any => (isObject(val) ? reactive(val) : val) +const convert = (val: T): T => + isObject(val) ? reactive(val) : val export function ref(raw: T): T export function ref(raw: T): Ref -export function ref(raw: any) { +export function ref(raw: unknown) { if (isRef(raw)) { return raw } raw = convert(raw) - const v = { + const r = { _isRef: true, get value() { - track(v, OperationTypes.GET, '') + track(r, OperationTypes.GET, '') return raw }, set value(newVal) { raw = convert(newVal) - trigger(v, OperationTypes.SET, '') + trigger(r, OperationTypes.SET, '') } } - return v as Ref + return r as Ref } -export function isRef(v: any): v is Ref { - return v ? v._isRef === true : false +export function isRef(r: any): r is Ref { + return r ? r._isRef === true : false } export function toRefs( @@ -61,13 +63,6 @@ function toProxyRef( } } -type BailTypes = - | Function - | Map - | Set - | WeakMap - | WeakSet - // Recursively unwraps nested value bindings. export type UnwrapRef = { cRef: T extends ComputedRef ? UnwrapRef : T @@ -77,9 +72,11 @@ export type UnwrapRef = { }[T extends ComputedRef ? 'cRef' : T extends Ref - ? 'ref' - : T extends Array - ? 'array' - : T extends BailTypes - ? 'ref' // bail out on types that shouldn't be unwrapped - : T extends object ? 'object' : 'ref'] + ? 'ref' + : T extends Array + ? 'array' + : T extends Function | CollectionTypes + ? 'ref' // bail out on types that shouldn't be unwrapped + : T extends object + ? 'object' + : 'ref'] diff --git a/packages/runtime-core/src/apiCreateComponent.ts b/packages/runtime-core/src/apiCreateComponent.ts index 1979d231..6353f4f0 100644 --- a/packages/runtime-core/src/apiCreateComponent.ts +++ b/packages/runtime-core/src/apiCreateComponent.ts @@ -77,6 +77,6 @@ export function createComponent< } // implementation, close to no-op -export function createComponent(options: any) { +export function createComponent(options: unknown) { return isFunction(options) ? { setup: options } : options } diff --git a/packages/runtime-core/src/apiInject.ts b/packages/runtime-core/src/apiInject.ts index 7eb076f1..a83a1ece 100644 --- a/packages/runtime-core/src/apiInject.ts +++ b/packages/runtime-core/src/apiInject.ts @@ -27,7 +27,10 @@ export function provide(key: InjectionKey | string, value: T) { export function inject(key: InjectionKey | string): T | undefined export function inject(key: InjectionKey | string, defaultValue: T): T -export function inject(key: InjectionKey | string, defaultValue?: any) { +export function inject( + key: InjectionKey | string, + defaultValue?: unknown +) { if (currentInstance) { const provides = currentInstance.provides if (key in provides) { diff --git a/packages/runtime-core/src/apiLifecycle.ts b/packages/runtime-core/src/apiLifecycle.ts index 533cc39a..9e8709f2 100644 --- a/packages/runtime-core/src/apiLifecycle.ts +++ b/packages/runtime-core/src/apiLifecycle.ts @@ -16,7 +16,7 @@ function injectHook( target: ComponentInternalInstance | null ) { if (target) { - ;(target[type] || (target[type] = [])).push((...args: any[]) => { + ;(target[type] || (target[type] = [])).push((...args: unknown[]) => { if (target.isUnmounted) { return } diff --git a/packages/runtime-core/src/apiOptions.ts b/packages/runtime-core/src/apiOptions.ts index d0327f1c..4d50317d 100644 --- a/packages/runtime-core/src/apiOptions.ts +++ b/packages/runtime-core/src/apiOptions.ts @@ -15,7 +15,7 @@ import { NOOP } from '@vue/shared' import { computed } from './apiReactivity' -import { watch, WatchOptions, CleanupRegistrator } from './apiWatch' +import { watch, WatchOptions, WatchHandler } from './apiWatch' import { provide, inject } from './apiInject' import { onBeforeMount, @@ -40,7 +40,7 @@ import { Directive } from './directives' import { ComponentPublicInstance } from './componentProxy' import { warn } from './warning' -interface ComponentOptionsBase< +export interface ComponentOptionsBase< Props, RawBindings, D, @@ -119,12 +119,6 @@ export type ExtractComputedReturns = { : ReturnType } -export type WatchHandler = ( - val: T, - oldVal: T, - onCleanup: CleanupRegistrator -) => any - type ComponentWatchOptions = Record< string, string | WatchHandler | { handler: WatchHandler } & WatchOptions @@ -134,7 +128,7 @@ type ComponentInjectOptions = | string[] | Record< string | symbol, - string | symbol | { from: string | symbol; default?: any } + string | symbol | { from: string | symbol; default?: unknown } > // TODO type inference for these options @@ -294,12 +288,12 @@ export function applyOptions( set: isFunction(set) ? set.bind(ctx) : __DEV__ - ? () => { - warn( - `Computed property "${key}" was assigned to but it has no setter.` - ) - } - : NOOP + ? () => { + warn( + `Computed property "${key}" was assigned to but it has no setter.` + ) + } + : NOOP }) } else if (__DEV__) { warn(`Computed property "${key}" has no getter.`) diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 2127a4ee..ff899d94 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -21,7 +21,12 @@ import { } from './errorHandling' import { onBeforeUnmount } from './apiLifecycle' import { queuePostRenderEffect } from './createRenderer' -import { WatchHandler } from './apiOptions' + +export type WatchHandler = ( + value: T, + oldValue: T, + onCleanup: CleanupRegistrator +) => any export interface WatchOptions { lazy?: boolean @@ -58,11 +63,7 @@ export function watch( // overload #3: array of multiple sources + cb export function watch[]>( sources: T, - cb: ( - newValues: MapSources, - oldValues: MapSources, - onCleanup: CleanupRegistrator - ) => any, + cb: WatchHandler>, options?: WatchOptions ): StopHandle @@ -84,9 +85,7 @@ export function watch( function doWatch( source: WatcherSource | WatcherSource[] | SimpleEffect, - cb: - | ((newValue: any, oldValue: any, onCleanup: CleanupRegistrator) => any) - | null, + cb: WatchHandler | null, { lazy, deep, flush, onTrack, onTrigger }: WatchOptions = EMPTY_OBJ ): StopHandle { const instance = currentInstance @@ -95,11 +94,10 @@ function doWatch( let getter: () => any if (isArray(source)) { getter = () => - source.map( - s => - isRef(s) - ? s.value - : callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) + source.map(s => + isRef(s) + ? s.value + : callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) ) } else if (isRef(source)) { getter = () => source.value @@ -218,7 +216,7 @@ export function instanceWatch( return stop } -function traverse(value: any, seen: Set = new Set()) { +function traverse(value: unknown, seen: Set = new Set()) { if (!isObject(value) || seen.has(value)) { return } diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index da5f8a71..909d04ce 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -60,7 +60,7 @@ export const enum LifecycleHooks { ERROR_CAPTURED = 'ec' } -export type Emit = ((event: string, ...args: unknown[]) => void) +export type Emit = (event: string, ...args: unknown[]) => void export interface SetupContext { attrs: Data @@ -86,13 +86,13 @@ export interface ComponentInternalInstance { accessCache: Data | null // cache for render function values that rely on _ctx but won't need updates // after initialized (e.g. inline handlers) - renderCache: any[] | null + renderCache: Function[] | null components: Record directives: Record asyncDep: Promise | null - asyncResult: any + asyncResult: unknown asyncResolved: boolean // the rest are only for stateful components diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 25e00ee2..9bd682a3 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -30,12 +30,12 @@ interface PropOptions { type?: PropType | true | null required?: boolean default?: T | null | undefined | (() => T | null | undefined) - validator?(value: any): boolean + validator?(value: unknown): boolean } export type PropType = PropConstructor | PropConstructor[] -type PropConstructor = { new (...args: any[]): T & object } | { (): T } +type PropConstructor = { new (...args: any[]): T & object } | { (): T } type RequiredKeys = { [K in keyof T]: T[K] extends @@ -53,10 +53,12 @@ type OptionalKeys = Exclude< type InferPropType = T extends null ? any // null & true would fail to infer : T extends { type: null | true } - ? any // somehow `ObjectConstructor` when inferred from { (): T } becomes `any` - : T extends ObjectConstructor | { type: ObjectConstructor } - ? { [key: string]: any } - : T extends Prop ? V : T + ? any // somehow `ObjectConstructor` when inferred from { (): T } becomes `any` + : T extends ObjectConstructor | { type: ObjectConstructor } + ? { [key: string]: any } + : T extends Prop + ? V + : T export type ExtractPropTypes< O, @@ -96,7 +98,7 @@ type NormalizedPropsOptions = Record export function resolveProps( instance: ComponentInternalInstance, - rawProps: any, + rawProps: Data | null, _options: ComponentPropsOptions | void ) { const hasDeclaredProps = _options != null @@ -105,18 +107,18 @@ export function resolveProps( return } - const props: any = {} - let attrs: any = void 0 + const props: Data = {} + let attrs: Data | undefined = void 0 // update the instance propsProxy (passed to setup()) to trigger potential // changes const propsProxy = instance.propsProxy const setProp = propsProxy - ? (key: string, val: any) => { + ? (key: string, val: unknown) => { props[key] = val propsProxy[key] = val } - : (key: string, val: any) => { + : (key: string, val: unknown) => { props[key] = val } @@ -192,7 +194,7 @@ export function resolveProps( instance.attrs = options ? __DEV__ && attrs != null ? readonly(attrs) - : attrs + : attrs! : instance.props } @@ -279,8 +281,8 @@ type AssertionResult = { function validateProp( name: string, - value: any, - prop: PropOptions, + value: unknown, + prop: PropOptions, isAbsent: boolean ) { const { type, required, validator } = prop @@ -317,7 +319,7 @@ function validateProp( const simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/ -function assertType(value: any, type: PropConstructor): AssertionResult { +function assertType(value: unknown, type: PropConstructor): AssertionResult { let valid const expectedType = getType(type) if (simpleCheckRE.test(expectedType)) { @@ -342,7 +344,7 @@ function assertType(value: any, type: PropConstructor): AssertionResult { function getInvalidTypeMessage( name: string, - value: any, + value: unknown, expectedTypes: string[] ): string { let message = @@ -368,7 +370,7 @@ function getInvalidTypeMessage( return message } -function styleValue(value: any, type: string): string { +function styleValue(value: unknown, type: string): string { if (type === 'String') { return `"${value}"` } else if (type === 'Number') { @@ -378,7 +380,7 @@ function styleValue(value: any, type: string): string { } } -function toRawType(value: any): string { +function toRawType(value: unknown): string { return toTypeString(value).slice(8, -1) } diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 32dd4eda..61132839 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -2,7 +2,12 @@ import { ComponentInternalInstance, Data, Emit } from './component' import { nextTick } from './scheduler' import { instanceWatch } from './apiWatch' import { EMPTY_OBJ, hasOwn, isGloballyWhitelisted } from '@vue/shared' -import { ExtractComputedReturns } from './apiOptions' +import { + ExtractComputedReturns, + ComponentOptionsBase, + ComputedOptions, + MethodOptions +} from './apiOptions' import { UnwrapRef, ReactiveEffect } from '@vue/reactivity' import { warn } from './warning' @@ -12,8 +17,8 @@ export type ComponentPublicInstance< P = {}, B = {}, D = {}, - C = {}, - M = {}, + C extends ComputedOptions = {}, + M extends MethodOptions = {}, PublicProps = P > = { [key: string]: any @@ -26,7 +31,7 @@ export type ComponentPublicInstance< $parent: ComponentInternalInstance | null $emit: Emit $el: any - $options: any + $options: ComponentOptionsBase $forceUpdate: ReactiveEffect $nextTick: typeof nextTick $watch: typeof instanceWatch @@ -134,7 +139,10 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { if (__RUNTIME_COMPILE__) { // this trap is only called in browser-compiled render functions that use // `with (this) {}` - PublicInstanceProxyHandlers.has = (_: any, key: string): boolean => { + PublicInstanceProxyHandlers.has = ( + _: ComponentInternalInstance, + key: string + ): boolean => { return key[0] !== '_' && !isGloballyWhitelisted(key) } } diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index 572c7ddc..253c42c9 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -14,7 +14,8 @@ import { createComponentInstance, setupStatefulComponent, handleSetupResult, - Component + Component, + Data } from './component' import { renderComponentRoot, @@ -36,7 +37,8 @@ import { ReactiveEffectOptions, isRef, Ref, - toRaw + toRaw, + DebuggerEvent } from '@vue/reactivity' import { resolveProps } from './componentProps' import { resolveSlots } from './componentSlots' @@ -70,7 +72,7 @@ function isSameType(n1: VNode, n2: VNode): boolean { return n1.type === n2.type && n1.key === n2.key } -function invokeHooks(hooks: Function[], arg?: any) { +function invokeHooks(hooks: Function[], arg?: DebuggerEvent) { for (let i = 0; i < hooks.length; i++) { hooks[i](arg) } @@ -555,8 +557,8 @@ export function createRenderer< function patchProps( el: HostElement, vnode: HostVNode, - oldProps: any, - newProps: any, + oldProps: Data, + newProps: Data, parentComponent: ComponentInternalInstance | null, parentSuspense: HostSuspenseBoundary | null, isSVG: boolean @@ -1160,72 +1162,83 @@ export function createRenderer< ) { // create reactive effect for rendering let mounted = false - instance.update = effect(function componentEffect() { - if (!mounted) { - const subTree = (instance.subTree = renderComponentRoot(instance)) - // beforeMount hook - if (instance.bm !== null) { - invokeHooks(instance.bm) - } - patch(null, subTree, container, anchor, instance, parentSuspense, isSVG) - initialVNode.el = subTree.el - // mounted hook - if (instance.m !== null) { - queuePostRenderEffect(instance.m, parentSuspense) - } - mounted = true - } else { - // updateComponent - // This is triggered by mutation of component's own state (next: null) - // OR parent calling processComponent (next: HostVNode) - const { next } = instance + instance.update = effect( + function componentEffect() { + if (!mounted) { + const subTree = (instance.subTree = renderComponentRoot(instance)) + // beforeMount hook + if (instance.bm !== null) { + invokeHooks(instance.bm) + } + patch( + null, + subTree, + container, + anchor, + instance, + parentSuspense, + isSVG + ) + initialVNode.el = subTree.el + // mounted hook + if (instance.m !== null) { + queuePostRenderEffect(instance.m, parentSuspense) + } + mounted = true + } else { + // updateComponent + // This is triggered by mutation of component's own state (next: null) + // OR parent calling processComponent (next: HostVNode) + const { next } = instance - if (__DEV__) { - pushWarningContext(next || instance.vnode) - } + if (__DEV__) { + pushWarningContext(next || instance.vnode) + } - if (next !== null) { - updateComponentPreRender(instance, next) - } - const prevTree = instance.subTree - const nextTree = (instance.subTree = renderComponentRoot(instance)) - // beforeUpdate hook - if (instance.bu !== null) { - invokeHooks(instance.bu) - } - // reset refs - // only needed if previous patch had refs - if (instance.refs !== EMPTY_OBJ) { - instance.refs = {} - } - patch( - prevTree, - nextTree, - // parent may have changed if it's in a portal - hostParentNode(prevTree.el as HostNode) as HostElement, - // anchor may have changed if it's in a fragment - getNextHostNode(prevTree), - instance, - parentSuspense, - isSVG - ) - instance.vnode.el = nextTree.el - if (next === null) { - // self-triggered update. In case of HOC, update parent component - // vnode el. HOC is indicated by parent instance's subTree pointing - // to child component's vnode - updateHOCHostEl(instance, nextTree.el) - } - // updated hook - if (instance.u !== null) { - queuePostRenderEffect(instance.u, parentSuspense) - } + if (next !== null) { + updateComponentPreRender(instance, next) + } + const prevTree = instance.subTree + const nextTree = (instance.subTree = renderComponentRoot(instance)) + // beforeUpdate hook + if (instance.bu !== null) { + invokeHooks(instance.bu) + } + // reset refs + // only needed if previous patch had refs + if (instance.refs !== EMPTY_OBJ) { + instance.refs = {} + } + patch( + prevTree, + nextTree, + // parent may have changed if it's in a portal + hostParentNode(prevTree.el as HostNode) as HostElement, + // anchor may have changed if it's in a fragment + getNextHostNode(prevTree), + instance, + parentSuspense, + isSVG + ) + instance.vnode.el = nextTree.el + if (next === null) { + // self-triggered update. In case of HOC, update parent component + // vnode el. HOC is indicated by parent instance's subTree pointing + // to child component's vnode + updateHOCHostEl(instance, nextTree.el) + } + // updated hook + if (instance.u !== null) { + queuePostRenderEffect(instance.u, parentSuspense) + } - if (__DEV__) { - popWarningContext() + if (__DEV__) { + popWarningContext() + } } - } - }, __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions) + }, + __DEV__ ? createDevEffectOptions(instance) : prodEffectOptions + ) } function updateComponentPreRender( diff --git a/packages/runtime-core/src/directives.ts b/packages/runtime-core/src/directives.ts index 079573eb..839b17ad 100644 --- a/packages/runtime-core/src/directives.ts +++ b/packages/runtime-core/src/directives.ts @@ -65,7 +65,7 @@ function applyDirective( props: Record, instance: ComponentInternalInstance, directive: Directive, - value?: any, + value?: unknown, arg?: string, modifiers: DirectiveModifiers = EMPTY_OBJ ) { diff --git a/packages/runtime-core/src/errorHandling.ts b/packages/runtime-core/src/errorHandling.ts index a17b0546..d576ff4a 100644 --- a/packages/runtime-core/src/errorHandling.ts +++ b/packages/runtime-core/src/errorHandling.ts @@ -54,9 +54,9 @@ export function callWithErrorHandling( fn: Function, instance: ComponentInternalInstance | null, type: ErrorTypes, - args?: any[] + args?: unknown[] ) { - let res: any + let res try { res = args ? fn(...args) : fn() } catch (err) { @@ -69,7 +69,7 @@ export function callWithAsyncErrorHandling( fn: Function | Function[], instance: ComponentInternalInstance | null, type: ErrorTypes, - args?: any[] + args?: unknown[] ) { if (isFunction(fn)) { const res = callWithErrorHandling(fn, instance, type, args) diff --git a/packages/runtime-core/src/helpers/renderList.ts b/packages/runtime-core/src/helpers/renderList.ts index 0150b857..693c87bc 100644 --- a/packages/runtime-core/src/helpers/renderList.ts +++ b/packages/runtime-core/src/helpers/renderList.ts @@ -2,8 +2,12 @@ import { VNodeChild } from '../vnode' import { isArray, isString, isObject } from '@vue/shared' export function renderList( - source: any, - renderItem: (value: any, key: string | number, index?: number) => VNodeChild + source: unknown, + renderItem: ( + value: unknown, + key: string | number, + index?: number + ) => VNodeChild ): VNodeChild[] { let ret: VNodeChild[] if (isArray(source) || isString(source)) { diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index e2f1f2ea..7c1635d2 100644 --- a/packages/runtime-core/src/helpers/renderSlot.ts +++ b/packages/runtime-core/src/helpers/renderSlot.ts @@ -1,3 +1,4 @@ +import { Data } from '../component' import { Slot } from '../componentSlots' import { VNodeChildren, @@ -11,7 +12,7 @@ import { PatchFlags } from '@vue/shared' export function renderSlot( slots: Record, name: string, - props: any = {}, + props: Data = {}, // this is not a user-facing function, so the fallback is always generated by // the compiler and guaranteed to be an array fallback?: VNodeChildren diff --git a/packages/runtime-core/src/helpers/toString.ts b/packages/runtime-core/src/helpers/toString.ts index 92879b89..8e8ee56b 100644 --- a/packages/runtime-core/src/helpers/toString.ts +++ b/packages/runtime-core/src/helpers/toString.ts @@ -1,10 +1,10 @@ import { isArray, isPlainObject, objectToString } from '@vue/shared' // for converting {{ interpolation }} values to displayed strings. -export function toString(val: any): string { +export function toString(val: unknown): string { return val == null ? '' : isArray(val) || (isPlainObject(val) && val.toString === objectToString) - ? JSON.stringify(val, null, 2) - : String(val) + ? JSON.stringify(val, null, 2) + : String(val) } diff --git a/packages/runtime-dom/src/modules/events.ts b/packages/runtime-dom/src/modules/events.ts index d3a5f8e4..11b060a8 100644 --- a/packages/runtime-dom/src/modules/events.ts +++ b/packages/runtime-dom/src/modules/events.ts @@ -117,7 +117,7 @@ export function patchEvent( } function createInvoker( - initialValue: any, + initialValue: EventValue, instance: ComponentInternalInstance | null ) { const invoker: Invoker = (e: Event) => {