diff --git a/README.md b/README.md index 005ab0c..db6494a 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ annil(安奈儿)是微信小程序原生开发插件,其提供的API功能更强 - 可选 ```bash - npm typescript miniprogram-api-typings --save-dev + npm typescript --save-dev ``` ```bash @@ -93,8 +93,6 @@ annil(安奈儿)是微信小程序原生开发插件,其提供的API功能更强 module.exports = require("./mobx.cjs.production.min.js"); ``` - > 另外,构建时会出现`node_modules/miniprogram-api-typings/index.d.ts.js: Npm package entry file not found`错误,这是因为annil插件把官方类型库`miniprogram-api-typings`加入到生产依赖中,而npm构建时找不到它的生产目录所致,无视即可。还需删除`miniprogram_npm`下的`hry-types`目录(annil依赖的类型工具库)。 - 3. 配置tsconfig.json(使用ts开发时) ```json { @@ -102,7 +100,9 @@ annil(安奈儿)是微信小程序原生开发插件,其提供的API功能更强 // ... "lib": ["ES2022"], "skipLibCheck": true, - "types": ["miniprogram-api-typings", "mobx"] + "strict": true, + "strictFunctionTypes": false, // 解决给事件参数e重定义类型报错的问题 + "types": ["miniprogram-api-typings"] } // ... } diff --git a/jest.config.ts b/jest.config.ts index adaea4c..7b254c1 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -12,6 +12,7 @@ export const config = { "./src/**/*.ts", "!src/**/*.test.ts", "!src/api/navigateTo.ts", + "!src/inject.ts", "!src/thirdLib/**", ], testMatch: [ diff --git a/jest/events/events.test.ts b/jest/events/events.test.ts index 6c4b312..a9fc090 100644 --- a/jest/events/events.test.ts +++ b/jest/events/events.test.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ - import simulate from "miniprogram-simulate"; import path from "path"; diff --git a/jest/events/events.ts b/jest/events/events.ts index 93c97fa..9b756f0 100644 --- a/jest/events/events.ts +++ b/jest/events/events.ts @@ -14,7 +14,7 @@ const subA = SubComponent()({ type Root = typeof rootComponent; -export const rootComponent = RootComponent()({ +const rootComponent = RootComponent()({ data: { id: "", }, diff --git a/jest/inject/duplicate/duplicate.json b/jest/inject/duplicate/duplicate.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/jest/inject/duplicate/duplicate.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/jest/inject/duplicate/duplicate.test.ts b/jest/inject/duplicate/duplicate.test.ts new file mode 100644 index 0000000..4180ec5 --- /dev/null +++ b/jest/inject/duplicate/duplicate.test.ts @@ -0,0 +1,50 @@ +import simulate from "miniprogram-simulate"; +import path from "path"; +import { instanceConfig } from "../../../src"; +import { BBeforeCreate } from "../../../src/behaviors/BbeforeCreated"; +import { BComputedAndWatch } from "../../../src/behaviors/BComputedAndWatch"; +import { BStore } from "../../../src/behaviors/BStore"; +export const checkData = { + options: {} as object | undefined, + data: {} as any, + behaviors: [] as string[], +}; + +const behavior = Behavior({}); + +// 注入options配置 +// @ts-ignore +instanceConfig.setInjectInfo({ + options: { + addGlobalClass: true, + multipleSlots: true, + pureDataPattern: /^_/, + virtualHost: true, + }, + data: { + injectStr: "string", + }, + behaviors: [behavior], +}); + +describe("inject数据被组件数据覆盖", () => { + const id = simulate.load(path.resolve(__dirname, "duplicate")); + const comp = simulate.render(id); + const parent = document.createElement("parent-wrapper"); + + comp.attach(parent); + + test("注入options、data、behaviors", () => { + expect(checkData.options).toStrictEqual({ + classPrefix: "main", // miniprogram-simulate 定义的 + addGlobalClass: false, + multipleSlots: false, + pureDataPattern: /^__/, + virtualHost: false, + }); + + expect(checkData.data.injectStr).toBe("changed"); + + expect(checkData.behaviors).toStrictEqual([BStore, BComputedAndWatch, behavior, BBeforeCreate]); + }); +}); diff --git a/jest/inject/duplicate/duplicate.ts b/jest/inject/duplicate/duplicate.ts new file mode 100644 index 0000000..2578d3b --- /dev/null +++ b/jest/inject/duplicate/duplicate.ts @@ -0,0 +1,28 @@ +import { DefineComponent, RootComponent } from "../../../src"; +import { checkData } from "./duplicate.test"; + +const rootComponent = RootComponent()({ + options: { + addGlobalClass: false, + multipleSlots: false, + pureDataPattern: /^__/, + virtualHost: false, + }, + data: { + injectStr: "changed", + }, + lifetimes: { + beforeCreate(opt) { + checkData.options = opt.options; + + checkData.data = opt.data; + + checkData.behaviors = opt.behaviors; + }, + }, +}); + +DefineComponent({ + name: "injectNormal", + rootComponent, +}); diff --git a/jest/inject/duplicate/duplicate.wxml b/jest/inject/duplicate/duplicate.wxml new file mode 100644 index 0000000..e69de29 diff --git a/jest/inject/normal/normal.json b/jest/inject/normal/normal.json new file mode 100644 index 0000000..a89ef4d --- /dev/null +++ b/jest/inject/normal/normal.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/jest/inject/normal/normal.test.ts b/jest/inject/normal/normal.test.ts new file mode 100644 index 0000000..1342e60 --- /dev/null +++ b/jest/inject/normal/normal.test.ts @@ -0,0 +1,44 @@ +import simulate from "miniprogram-simulate"; +import path from "path"; +import { instanceConfig } from "../../../src"; + +export const checkData = { + options: {} as object | undefined, + data: {} as any, +}; + +const options = { + addGlobalClass: true, + multipleSlots: true, + pureDataPattern: /^_/, + virtualHost: true, +}; + +// 注入options配置 +// @ts-ignore +instanceConfig.setInjectInfo({ + options, + data: { + injectStr: "string", + }, + store: { + injectTheme: () => "dark", + }, +}); + +describe("inject-无重复", () => { + const id = simulate.load(path.resolve(__dirname, "normal")); + const comp = simulate.render(id); + const parent = document.createElement("parent-wrapper"); + + comp.attach(parent); + + test("注入options、data、store", () => { + expect(checkData.options).toStrictEqual({ + classPrefix: "main", // miniprogram-simulate 定义的 + ...options, + }); + + expect(checkData.data).toStrictEqual({ injectTheme: "dark", injectStr: "string" }); + }); +}); diff --git a/jest/inject/normal/normal.ts b/jest/inject/normal/normal.ts new file mode 100644 index 0000000..8eeba02 --- /dev/null +++ b/jest/inject/normal/normal.ts @@ -0,0 +1,17 @@ +import { DefineComponent, RootComponent } from "../../../src"; +import { checkData } from "./normal.test"; + +const rootComponent = RootComponent()({ + lifetimes: { + beforeCreate(opt) { + checkData.options = opt.options!; + + checkData.data = opt.data; + }, + }, +}); + +DefineComponent({ + name: "injectNormal", + rootComponent, +}); diff --git a/jest/inject/normal/normal.wxml b/jest/inject/normal/normal.wxml new file mode 100644 index 0000000..e69de29 diff --git a/package-lock.json b/package-lock.json index 12437d9..7b7182d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "annil", "version": "1.4.0", "license": "MIT", - "dependencies": { - "hry-types": "^0.17.0" - }, "devDependencies": { "@commitlint/config-conventional": "^17.6.5", "@types/jest": "^29.5.5", @@ -29,6 +26,7 @@ "typescript": "^5.3.2" }, "peerDependencies": { + "hry-types": "^0.17.0", "miniprogram-api-typings": "^3.12.2" } }, @@ -3776,8 +3774,9 @@ }, "node_modules/hry-types": { "version": "0.17.0", - "resolved": "https://registry.npmjs.org/hry-types/-/hry-types-0.17.0.tgz", - "integrity": "sha512-fE3AcVUgJ7XsZAepRCaF2KAK+FoGJegulaSPTxvk1+2Ut6mjUKrbEoucJVULQz+hh/P+hW8FDNZMldZNFoMikg==" + "resolved": "https://registry.npmmirror.com/hry-types/-/hry-types-0.17.0.tgz", + "integrity": "sha512-fE3AcVUgJ7XsZAepRCaF2KAK+FoGJegulaSPTxvk1+2Ut6mjUKrbEoucJVULQz+hh/P+hW8FDNZMldZNFoMikg==", + "peer": true }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", diff --git a/package.json b/package.json index a367965..a455e61 100644 --- a/package.json +++ b/package.json @@ -53,10 +53,8 @@ ], "author": "missannil", "license": "MIT", - "dependencies": { - "hry-types": "^0.17.0" - }, "peerDependencies": { + "hry-types": "^0.17.0", "miniprogram-api-typings": "^3.12.2" } } diff --git a/src/api/DefineComponent/collectOptionsForComponent.ts b/src/api/DefineComponent/collectOptionsForComponent.ts index 246c458..650e27f 100644 --- a/src/api/DefineComponent/collectOptionsForComponent.ts +++ b/src/api/DefineComponent/collectOptionsForComponent.ts @@ -1,8 +1,10 @@ import type { Func } from "hry-types/src/Misc/_api"; +import { instanceConfig } from "../.."; import { BBeforeCreate } from "../../behaviors/BbeforeCreated"; import { BComputedAndWatch } from "../../behaviors/BComputedAndWatch"; import type { ComputedCache, Instance } from "../../behaviors/BComputedAndWatch/types"; import { BStore } from "../../behaviors/BStore"; +import { Assign } from "../../types/Assign"; import type { WMComponent } from "../../types/OfficialTypeAlias"; import { INNERMARKER } from "../../utils/InnerMarker"; import { isEmptyObject } from "../../utils/isEmptyObject"; @@ -292,6 +294,44 @@ function collectRootComponentOption( otherFieldsHandle(finalOptions, rootComponentOptions); } +/** + * 合并 source 对象字段到 target字段 + * @remarks 规则: + * 1. behaviors字段 源对象在前 + * 2. 对象字段 源覆盖目标 + * @param target - 目标对象 + * @param source - 源对象 + * @returns 按规则合并后的对象 + */ +function merge(target: Target, source: Source): Assign { + for (const key in source) { + const sourceVal = source[key]; + if (key in target) { + // @ts-ignore + const targetVal = target[key]; + switch (key) { + case "behaviors": + { + // @ts-ignore + target[key] = [...sourceVal, ...targetVal]; + } + break; + + default: + { + // @ts-ignore 源覆盖目标 + target[key] = Object.assign(targetVal, sourceVal); + } + break; + } + } else { + // @ts-ignore + target[key] = sourceVal; + } + } + + return target as unknown as Assign; +} /** * 返回一个由rootComponentOption和subComponentsList配置整合的对象 * @param rootComponentOption - @@ -303,18 +343,14 @@ export function collectOptionsForComponent( ): FinalOptionsOfComponent { const rootComponentOption = defineComponentOption.rootComponent; const subComponentsList = defineComponentOption.subComponents; - const finalOptionsForComponent: FinalOptionsOfComponent = { - options: { - addGlobalClass: true, // "styleIsolation": "apply-shared" - multipleSlots: true, - pureDataPattern: /^_/, - virtualHost: true, - }, - behaviors: [BStore, BComputedAndWatch], - methods: {}, + + const finalOptionsForComponent: FinalOptionsOfComponent = merge(instanceConfig.injectInfo || {}, { observers: {}, data: {}, - }; + methods: {}, + behaviors: [BStore, BComputedAndWatch], + }); + /** * 有些字段配置同时存在根组件和子组件当中(如pageLifetimes,lifetimes,watch字段), 且key相同值类型为函数。funcConfig对象用于收集这些配置为数组形式,最终再一起整合进finalOptionsForComponent配置中。即funcConfig是一个临时中介对象。 */ @@ -350,7 +386,7 @@ export function collectOptionsForComponent( /* istanbul ignore next: miniprogram-simulate(当前版本 1.6.1) 无法测试页面 */ finalOptionsForComponent.isPage // 页面时删除预设的虚拟组件字段 - && Reflect.deleteProperty(finalOptionsForComponent.options!, "virtualHost"); + && finalOptionsForComponent.options && Reflect.deleteProperty(finalOptionsForComponent.options, "virtualHost"); // BBeforeCreate在最后面,让BeforeCreate生命周期运行在最终建立组件时。 finalOptionsForComponent.behaviors!.push(BBeforeCreate); diff --git a/src/api/DefineComponent/index.ts b/src/api/DefineComponent/index.ts index ff2ca89..c97e2d4 100644 --- a/src/api/DefineComponent/index.ts +++ b/src/api/DefineComponent/index.ts @@ -54,6 +54,7 @@ export type DefineComponentOption = { */ export const DefineComponent: DefineComponentConstructor = function(options): any { // console.log("---------------------------"); + Component( collectOptionsForComponent(options as DefineComponentOption) as any, ); diff --git a/src/api/InstanceInject/InstanceInject.ts b/src/api/InstanceInject/InstanceInject.ts deleted file mode 100644 index 33159f9..0000000 --- a/src/api/InstanceInject/InstanceInject.ts +++ /dev/null @@ -1,25 +0,0 @@ -// import type { WMComponentOption } from "../../types/officialAlias"; - -// // export type InjectMethodConstraint = Record; - -// // export type InjectDataConstraint = Record; - -// export abstract class Inject { -// public options?: WMComponentOption; -// // public methods?: InjectMethodConstraint; -// // public data?: InjectDataConstraint; -// } - -// /** -// * 实例注入接口,加入数据到所有实例中(当前仅支持data,methods,options字段),可在this上获取对应数据 响应式需函数返回方式 -// * @example -// */ -// export class InstanceInject extends Inject { -// private static _injectOption = new InstanceInject(); -// public static get InjectOption(): InstanceInject { -// return this._injectOption; -// } -// public static set InjectOption(options: InstanceInject) { -// this._injectOption = options; -// } -// } diff --git a/src/api/InstanceInject/instanceConfig.ts b/src/api/InstanceInject/instanceConfig.ts new file mode 100644 index 0000000..b89b2c3 --- /dev/null +++ b/src/api/InstanceInject/instanceConfig.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/explicit-member-accessibility */ + +import { ReturnTypeInObject } from "hry-types/src/Object/ReturnTypeInObject"; +import { WMComponentOption } from "../../types/OfficialTypeAlias"; +import { DataConstraint } from "../RootComponent/Data/DataConstraint"; +import { MethodsConstraint } from "../RootComponent/Methods/MethodsConstraint"; +import { StoreConstraint } from "../RootComponent/Store/StoreConstraint"; + +// 利用继承的多态性 使得IInjectInfo类型可由使用者外部定义 +interface BaseInjectInfo { + options?: WMComponentOption; + methods?: MethodsConstraint; + data?: DataConstraint; + store?: StoreConstraint; + behaviors?: string[]; +} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface IInjectInfo extends BaseInjectInfo { +} + +export type IInjectData = IInjectInfo["data"] & ReturnTypeInObject; + +export type IInjectMethods = IInjectInfo["methods"]; + +/** + * 实例配置接口 + */ +class InstanceConfig { + private info: { injectInfo?: IInjectInfo } = {}; + public get injectInfo() { + return this.info.injectInfo; + } + public setInjectInfo(info: IInjectInfo | undefined) { + info && (this.info.injectInfo = info); + } +} + +export const instanceConfig = new InstanceConfig(); diff --git a/src/api/InstanceInject/test/InjectConfig.ts b/src/api/InstanceInject/test/InjectConfig.ts deleted file mode 100644 index f0950ac..0000000 --- a/src/api/InstanceInject/test/InjectConfig.ts +++ /dev/null @@ -1,50 +0,0 @@ -// import { InstanceInject } from "../../.."; - -// import { observable } from "mobx"; -// import type { InjectDataConstraint, InjectMethodConstraint } from "../InstanceInject"; - -// const reactiveUser = observable({ -// name: "zhao", -// age: 18, -// }); - -// /** -// * @description 注入的data -// */ -// const data = { -// // 响应式数据 -// reactiveUser: () => reactiveUser, -// // 非响应式数据 -// injectStr: "injectStr", -// } satisfies InjectDataConstraint; -// /** -// * @description 注入的方法 -// */ -// const methods = { -// injectMethod(data: string) { -// console.log(data); -// }, -// } satisfies InjectMethodConstraint; -/** - * 注入的配置 - */ -// const options = { -// addGlobalClass: true, -// multipleSlots: true, -// pureDataPattern: /^_/, -// virtualHost: true, -// }; - -// InstanceInject.InjectOption = { -// // data, -// options, -// // methods, -// }; - -// 声明注入类型 -// declare module "../../.." { -// interface InstanceInject { -// data: typeof data; -// methods: typeof methods; -// } -// } diff --git a/src/api/InstanceInject/test/normal.test.ts b/src/api/InstanceInject/test/normal.test.ts new file mode 100644 index 0000000..41ba435 --- /dev/null +++ b/src/api/InstanceInject/test/normal.test.ts @@ -0,0 +1,40 @@ +import { Checking, Test } from "hry-types"; +import { RootComponent } from "../../RootComponent"; + +// 1. 注入字段无重复时 +RootComponent()({ + methods: { + testInjectTypes() { + Checking; + + Checking; + + Checking string, Test.Pass>; + }, + }, +}); + +// 2. 注入字段重复时,自身覆盖注入类型 +RootComponent()({ + data: { + // 覆盖注入的数据类型 + injectStr: 123, + }, + store: { + // 覆盖注入的数据类型 + injectTheme: (() => "aaa") as () => "aaa", + }, + methods: { + // 覆盖注入的方法类型 + injectMethod() { + return 123; + }, + testInjectTypes() { + Checking; + + Checking; + + Checking 123, Test.Pass>; + }, + }, +}); diff --git a/src/api/RootComponent/Computed/test/normal.test.ts b/src/api/RootComponent/Computed/test/normal.test.ts index 7e35938..25a9492 100644 --- a/src/api/RootComponent/Computed/test/normal.test.ts +++ b/src/api/RootComponent/Computed/test/normal.test.ts @@ -1,5 +1,6 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import { RootComponent } from "../.."; import type { Mock_User } from "../../Properties/test/normalRequired.test"; @@ -29,15 +30,17 @@ const RootDoc = RootComponent()({ // 3 this.data 类型是深度只读的 Checking< typeof this.data, - ReadonlyDeep<{ - firstName: string; - lastName: string; - fullName: string; - user: Mock_User; - prefix: string; - id_fullName: string; - readOnly: "str"; - }>, + ReadonlyDeep< + { + firstName: string; + lastName: string; + fullName: string; + user: Mock_User; + prefix: string; + id_fullName: string; + readOnly: "str"; + } & IInjectData + >, Test.Pass >; @@ -66,7 +69,7 @@ const noComputedFieldDoc = RootComponent()({ methods: { M1() { // 5.1 无computed,this.data中为{} - Checking; + Checking, Test.Pass>; }, }, }); @@ -81,7 +84,7 @@ const EmptyComputedFieldDoc = RootComponent()({ methods: { M1() { // 6.1 computed为{},this.data中为{} - Checking; + Checking, Test.Pass>; }, }, }); diff --git a/src/api/RootComponent/Data/test/normal.test.ts b/src/api/RootComponent/Data/test/normal.test.ts index e9a7788..42a0927 100644 --- a/src/api/RootComponent/Data/test/normal.test.ts +++ b/src/api/RootComponent/Data/test/normal.test.ts @@ -1,6 +1,7 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import { RootComponent } from "../.."; type Gender = "male" | "female"; @@ -15,7 +16,7 @@ const RootDoc = RootComponent()({ foo() { Checking< typeof this.data, - ReadonlyDeep<{ gender: Gender; num: number; _innernalFields: number }>, + ReadonlyDeep<{ gender: Gender; num: number; _innernalFields: number } & IInjectData>, Test.Pass >; }, @@ -36,7 +37,7 @@ const EmptyDataRootDoc = RootComponent()({ methods: { M1() { // 3.1 data为空对象时 this.data为{}类型 - Checking; + Checking, Test.Pass>; }, }, }); @@ -51,7 +52,7 @@ const noDataRootDoc = RootComponent()({ methods: { M1() { // 4.1 data为空对象时 this.data为{}类型 - Checking; + Checking, Test.Pass>; }, }, }); diff --git a/src/api/RootComponent/Instance/RootComponentInstance.ts b/src/api/RootComponent/Instance/RootComponentInstance.ts index 2b41a5f..ce76173 100644 --- a/src/api/RootComponent/Instance/RootComponentInstance.ts +++ b/src/api/RootComponent/Instance/RootComponentInstance.ts @@ -1,10 +1,11 @@ import type { ReadonlyDeep } from "hry-types/src/Any/_api"; import type { IfExtends } from "hry-types/src/Any/IfExtends"; -import type { Func } from "hry-types/src/Misc/Func"; import type { ComputeIntersection } from "hry-types/src/Object/ComputeIntersection"; import type { IReactionDisposer } from "mobx"; +import { Assign } from "../../../types/Assign"; import type { WMComponentInstance, WMInstanceMethods, WMPageInstance } from "../../../types/OfficialTypeAlias"; +import { IInjectData, IInjectMethods } from "../../InstanceInject/instanceConfig"; import type { CustomEventMethods } from "./CustomEventMethods"; import type { CustomSetData } from "./CustomSetData"; export type RootComponentInstance< @@ -23,11 +24,9 @@ export type RootComponentInstance< & CustomSetData & IfExtends<{}, StoreDoc, unknown, { disposer?: { [k in keyof StoreDoc]: IReactionDisposer }; - applySetData: Func; }> - & TMethods - & CustomEventMethods - & { data: ReadonlyDeep> }; + & Assign> + & { data: ReadonlyDeep>> }; export type ComponentInstance = RootComponentInstance; diff --git a/src/api/RootComponent/Instance/test/properties/mormal.test.ts b/src/api/RootComponent/Instance/test/properties/mormal.test.ts index 8172bf5..0418e9c 100644 --- a/src/api/RootComponent/Instance/test/properties/mormal.test.ts +++ b/src/api/RootComponent/Instance/test/properties/mormal.test.ts @@ -1,6 +1,7 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/ReadonlyDeep"; import { type DetailedType, RootComponent } from "../../../../.."; +import { IInjectData } from "../../../../InstanceInject/instanceConfig"; // 组件时 RootComponent()({ @@ -14,7 +15,11 @@ RootComponent()({ lifetimes: { attached() { // 组件实例对象格外添加null类型 - Checking, Test.Pass>; + Checking< + typeof this.data, + ReadonlyDeep<{ optionalObj: { name: string } | null; obj: object | null } & IInjectData>, + Test.Pass + >; }, }, }); diff --git a/src/api/RootComponent/Instance/test/setData/error.test.ts b/src/api/RootComponent/Instance/test/setData/error.test.ts index f0cae95..5082b4a 100644 --- a/src/api/RootComponent/Instance/test/setData/error.test.ts +++ b/src/api/RootComponent/Instance/test/setData/error.test.ts @@ -63,13 +63,3 @@ RootComponent()({ }, }, }); - -RootComponent()({ - store: {}, - lifetimes: { - attached() { - // @ts-expect-error 没有store字段时不可以调用applySetData - this.applySetData(); - }, - }, -}); diff --git a/src/api/RootComponent/Instance/test/setData/normal.test.ts b/src/api/RootComponent/Instance/test/setData/normal.test.ts index 67be02c..cfd75a5 100644 --- a/src/api/RootComponent/Instance/test/setData/normal.test.ts +++ b/src/api/RootComponent/Instance/test/setData/normal.test.ts @@ -46,9 +46,6 @@ RootComponent()({ runInAction(() => { store.name = "liil"; }); - - // 有store字段时可以调用applySetData - this.applySetData(); }, }, }); diff --git a/src/api/RootComponent/Properties/test/normalEmpty.test.ts b/src/api/RootComponent/Properties/test/normalEmpty.test.ts index c25213f..8935dbc 100644 --- a/src/api/RootComponent/Properties/test/normalEmpty.test.ts +++ b/src/api/RootComponent/Properties/test/normalEmpty.test.ts @@ -1,4 +1,6 @@ import { Checking, type Test } from "hry-types"; +import { ReadonlyDeep } from "hry-types/src/Any/_api"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import { RootComponent } from "../.."; /** @@ -9,7 +11,7 @@ const emptyObj = RootComponent()({ methods: { foo() { // 1 this.data 为空对象类型 - Checking; + Checking, Test.Pass>; }, }, }); @@ -28,7 +30,7 @@ const noProperties = RootComponent()({ methods: { foo() { // 3 this.data 为空对象类型 - Checking; + Checking, Test.Pass>; }, }, }); diff --git a/src/api/RootComponent/Properties/test/normalOptional.test.ts b/src/api/RootComponent/Properties/test/normalOptional.test.ts index 3cad6e6..6137173 100644 --- a/src/api/RootComponent/Properties/test/normalOptional.test.ts +++ b/src/api/RootComponent/Properties/test/normalOptional.test.ts @@ -1,6 +1,7 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; import type { DetailedType } from "../../../../types/DetailedType"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import { RootComponent } from "../.."; import { type Mock_User } from "./normalRequired.test"; @@ -43,14 +44,16 @@ const OptionalDoc = RootComponent()({ // 1. 内部this.data中的类型(去除可选) Checking< typeof this.data, - ReadonlyDeep<{ - optional_num: number; - optional_gender: "male" | "female"; - optional_tuple: [number, string, boolean]; - optional_obj: Mock_User | null; - optional_objOrNull: Mock_User | null; - optional_union: string | number; - }>, + ReadonlyDeep< + { + optional_num: number; + optional_gender: "male" | "female"; + optional_tuple: [number, string, boolean]; + optional_obj: Mock_User | null; + optional_objOrNull: Mock_User | null; + optional_union: string | number; + } & IInjectData + >, Test.Pass >; }, diff --git a/src/api/RootComponent/Properties/test/normalRequired.test.ts b/src/api/RootComponent/Properties/test/normalRequired.test.ts index 936dbe1..907b38a 100644 --- a/src/api/RootComponent/Properties/test/normalRequired.test.ts +++ b/src/api/RootComponent/Properties/test/normalRequired.test.ts @@ -2,6 +2,7 @@ import { Checking, type Test } from "hry-types"; import type { DetailedType } from "../../../../types/DetailedType"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import { RootComponent } from "../.."; import type { RequiredSingle, RequiredType, RequiredUnion } from "../PropertiesConstraint"; @@ -91,7 +92,7 @@ const RequiredDoc = RootComponent()({ methods: { foo() { // 1 this.data中的类型(对象类型加null) - Checking, Test.Pass>; + Checking, Test.Pass>; }, }, }); diff --git a/src/api/SubComponent/SubComputed/test/normal.test.ts b/src/api/SubComponent/SubComputed/test/normal.test.ts index 90b107d..3077408 100644 --- a/src/api/SubComponent/SubComputed/test/normal.test.ts +++ b/src/api/SubComponent/SubComputed/test/normal.test.ts @@ -2,6 +2,7 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; import type { ComponentDoc } from "../../../DefineComponent/ReturnType/ComponentDoc"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import type { Mock_User } from "../../../RootComponent/Properties/test/normalRequired.test"; import { SubComponent } from "../.."; @@ -80,17 +81,19 @@ SubComponent()({ // 5 this.data Checking< typeof this.data, - ReadonlyDeep<{ - num: number; - user: User | null; - SNum: number; - str: string; - bool: boolean; - aaa_num: number; - aaa_num123: 123; - aaa_str: "a"; - aaa_obj: Mock_User; - }>, + ReadonlyDeep< + { + num: number; + user: User | null; + SNum: number; + str: string; + bool: boolean; + aaa_num: number; + aaa_num123: 123; + aaa_str: "a"; + aaa_obj: Mock_User; + } & IInjectData + >, Test.Pass >; @@ -102,17 +105,19 @@ SubComponent()({ // 5 this.data 深度只读 Checking< typeof this.data, - ReadonlyDeep<{ - num: number; - user: User | null; - str: string; - SNum: number; - bool: boolean; - aaa_num: number; - aaa_num123: 123; - aaa_str: "a"; - aaa_obj: Mock_User; - }>, + ReadonlyDeep< + { + num: number; + user: User | null; + str: string; + SNum: number; + bool: boolean; + aaa_num: number; + aaa_num123: 123; + aaa_str: "a"; + aaa_obj: Mock_User; + } & IInjectData + >, Test.Pass >; }, diff --git a/src/api/SubComponent/SubData/test/normal.test.ts b/src/api/SubComponent/SubData/test/normal.test.ts index 3895d07..f764c20 100644 --- a/src/api/SubComponent/SubData/test/normal.test.ts +++ b/src/api/SubComponent/SubData/test/normal.test.ts @@ -2,6 +2,7 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; import type { ComponentDoc } from "../../../DefineComponent/ReturnType/ComponentDoc"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import type { Mock_User } from "../../../RootComponent/Properties/test/normalRequired.test"; import { SubComponent } from "../.."; @@ -51,12 +52,14 @@ SubComponent<{}, CompDoc>()({ // 4 this.data中的data配置数据 Checking< typeof this.data, - ReadonlyDeep<{ - aaa_str: "a"; - aaa_num: 123; - aaa_obj: null; - _aaa_str: string; - }>, + ReadonlyDeep< + { + aaa_str: "a"; + aaa_num: 123; + aaa_obj: null; + _aaa_str: string; + } & IInjectData + >, Test.Pass >; }, diff --git a/src/api/SubComponent/SubInstance/test/normal.test.ts b/src/api/SubComponent/SubInstance/test/normal.test.ts index c13a3b0..ef4b490 100644 --- a/src/api/SubComponent/SubInstance/test/normal.test.ts +++ b/src/api/SubComponent/SubInstance/test/normal.test.ts @@ -2,6 +2,7 @@ import { Checking, type Test } from "hry-types"; import type { ReadonlyDeep } from "hry-types/src/Any/_api"; import type { ComponentDoc } from "../../../DefineComponent/ReturnType/ComponentDoc"; +import { IInjectData } from "../../../InstanceInject/instanceConfig"; import type { Mock_User } from "../../../RootComponent/Properties/test/normalRequired.test"; import type { RootComponentDoc } from "../../../RootComponent/RootComponentDoc"; import { SubComponent } from "../.."; @@ -57,17 +58,19 @@ SubComponent()({ // this.data Checking< typeof this.data, - ReadonlyDeep<{ - // RootData - Pstr: string; - Pobj: Mock_User | null; - PoptionalObj: Mock_User; - Dnum: number; - Cnum: number; - // 自身Data - aaa_str: "str"; - _aaa_SubReactive: 123; - }>, + ReadonlyDeep< + { + // RootData + Pstr: string; + Pobj: Mock_User | null; + PoptionalObj: Mock_User; + Dnum: number; + Cnum: number; + // 自身Data + aaa_str: "str"; + _aaa_SubReactive: 123; + } & IInjectData + >, Test.Pass >; diff --git a/src/behaviors/BComputedAndWatch/data-tracer.ts b/src/behaviors/BComputedAndWatch/data-tracer.ts index b432148..1c8ec33 100644 --- a/src/behaviors/BComputedAndWatch/data-tracer.ts +++ b/src/behaviors/BComputedAndWatch/data-tracer.ts @@ -42,6 +42,7 @@ export function deepProxy( return deepProxy(val, dependences, curPath); }, + /* istanbul ignore next */ set(_target: object, prop: string) { throw Error(`${prop}字段是只读的`); }, diff --git a/src/behaviors/BComputedAndWatch/types.ts b/src/behaviors/BComputedAndWatch/types.ts index 2bdb8d5..a01ee9b 100644 --- a/src/behaviors/BComputedAndWatch/types.ts +++ b/src/behaviors/BComputedAndWatch/types.ts @@ -3,7 +3,6 @@ import type { ComponentInstance, PageInstance } from "../../api/RootComponent/In import type { ComputedDependence } from "./initComputed"; export type InstanceCustomFields = { - __pendingSetData__?: object | null; __storeConfig__?: () => Record unknown>; __computedStatus__?: "待更新" | "更新完毕"; __computedUpdater__: Func; diff --git a/src/index.ts b/src/index.ts index 28cd660..ae4d3f9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import { DefineComponent } from "./api/DefineComponent"; +import { type IInjectInfo, instanceConfig } from "./api/InstanceInject/instanceConfig"; import { navigateTo } from "./api/navigateTo"; import { RootComponent } from "./api/RootComponent"; import { SubComponent } from "./api/SubComponent"; @@ -23,6 +24,8 @@ export { DefineComponent, type DetailedType, type GenerateDoc, + type IInjectInfo, + instanceConfig, /* istanbul ignore next */ navigateTo, type ParamsEqual, diff --git a/src/inject.ts b/src/inject.ts new file mode 100644 index 0000000..bf47c45 --- /dev/null +++ b/src/inject.ts @@ -0,0 +1,34 @@ +import { observable, runInAction } from "mobx"; + +// 注入的响应式数据; +const themeStore = observable({ theme: wx.getSystemInfoSync().theme }); + +wx.onThemeChange((Res) => { + runInAction(() => { + themeStore.theme = Res.theme; + }); +}); + +// 注入的方法; +function injectMethod(data: string) { + return data; +} + +const data = { + injectStr: "injectStr", +}; +const methods = { + injectMethod, +}; +const store = { + injectTheme: () => themeStore.theme, +}; + +// 声明注入类型 js开发可以忽略 +declare module "./index" { + interface IInjectInfo { + data: typeof data; + store: typeof store; + methods: typeof methods; + } +} diff --git a/src/types/Assign.ts b/src/types/Assign.ts new file mode 100644 index 0000000..bcbbacb --- /dev/null +++ b/src/types/Assign.ts @@ -0,0 +1 @@ +export type Assign = Omit & O2; diff --git a/src/types/OfficialTypeAlias.ts b/src/types/OfficialTypeAlias.ts index 613aeca..d965a90 100644 --- a/src/types/OfficialTypeAlias.ts +++ b/src/types/OfficialTypeAlias.ts @@ -55,7 +55,7 @@ export type CurrentTargetDataset = WMCustomEvent<{}, {}, T>; */ export type TargetDataset = WMCustomEvent<{}, {}, {}, TargetDataset>; -export type WMComponentOption = WechatMiniprogram.Component.TrivialOption; +export type WMComponentOption = WechatMiniprogram.Component.ComponentOptions; export type WMNavigateToSuccessCallbackResult = WechatMiniprogram.NavigateToSuccessCallbackResult;