UNPKG

@msom/reaction

Version:

@msom/reaction

97 lines (95 loc) 2.89 kB
import { ComputedDecoratorUsedError, defineProperty, initComponentDefinition, isComponent, } from "@msom/common"; import { _computed, generateIObserver } from "../utils"; import { ComputedOption } from "../Computed"; /** * 计算属性装饰器 * 用于get计算属性和无参函数上 * @returns MethodDecorator */ export function computed<T>( option?: Omit<ComputedOption<T>, "method"> ): ( target: object, key: string | symbol, descriptor: TypedPropertyDescriptor<T> ) => TypedPropertyDescriptor<T> | void { return function (target, key, descriptor) { // 实例属性target为类的原型对象 // 静态属性target为类构造器 // 非静态 if (typeof target === "function") { throw new ComputedDecoratorUsedError({ NotStatic: true }); } if (!descriptor) { throw new ComputedDecoratorUsedError({ NotProperty: true }); } let method = descriptor.value as (() => T) | undefined; let methodType: "value" | "get" = "value"; if (typeof method !== "function") { method = descriptor.get; methodType = "get"; } if (typeof method !== "function") { throw new ComputedDecoratorUsedError({ defineMessage: () => { return `the method or accessor for getter ${String( key )} not be function.`; }, }); } if (method.length > 0) { console.warn( new ComputedDecoratorUsedError({ defineMessage: () => { return "the computed effct method should be no argument"; }, }).message ); return; } if (isComponent(target)) { // 初始化组件定义 const definition = initComponentDefinition(target); // 判断是否已经标记为响应式 if ( Reflect.has(definition.$observers, key) && definition.$observers[key] ) { throw new ComputedDecoratorUsedError({ defineMessage: () => { return `the computed method or computed property ${String( key )} is exist.`; }, }); } // 标记 defineProperty(definition.$observers, key, 7, "computed"); } const _method = method; descriptor[methodType] = function (this: any) { const create = generateIObserver.bind(this); return create(key, _computed, { ...option, method: _method.bind(this), }).get(); } as T & (() => T); const setter = descriptor.set; if (setter) { descriptor.set = function (this: any, value: T) { setter.call(this, value); const create = generateIObserver.bind(this); create(key, _computed, { ...option, method: _method.bind(this), }).notify(); }; } }; }