From aed4178c9fbdcbc66b3df604582a090bddeab77f Mon Sep 17 00:00:00 2001 From: Malash Date: Tue, 8 Jan 2019 11:23:50 +0800 Subject: [PATCH] add type-safe behavior --- types/weixin-app/index.d.ts | 85 +++++++++++++++++++++------- types/weixin-app/weixin-app-tests.ts | 31 +++++++++- 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/types/weixin-app/index.d.ts b/types/weixin-app/index.d.ts index 03e7936630..c4c46353d0 100644 --- a/types/weixin-app/index.d.ts +++ b/types/weixin-app/index.d.ts @@ -4,7 +4,7 @@ // AlexStacker // Jimexist // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.8 +// TypeScript Version: 3.0 declare namespace wx { // #region 基本参数 @@ -3729,13 +3729,44 @@ declare namespace wx { type DefaultProps = object | Record; + type UnionToIntersection = (U extends any ? (k: U) => void : never) extends (( + k: infer I, + ) => void) + ? I + : never; + + type ArrayType = T extends Array ? R : never; + + interface Behavior { + __DO_NOT_USE_INTERNAL_FIELD_DATA: Data; + __DO_NOT_USE_INTERNAL_FIELD_PROPS: Props; + __DO_NOT_USE_INTERNAL_FIELD_METHODS: Methods; + } + + type UnboxBehaviorData = T extends Behavior<{}, {}, {}> ? T['__DO_NOT_USE_INTERNAL_FIELD_DATA'] : {}; + type UnboxBehaviorProps = T extends Behavior<{}, {}, {}> ? T['__DO_NOT_USE_INTERNAL_FIELD_PROPS'] : {}; + type UnboxBehaviorMethod = T extends Behavior<{}, {}, {}> ? T['__DO_NOT_USE_INTERNAL_FIELD_METHODS'] : {}; + + type UnboxBehaviorsMethods< + Behaviors extends Array | string> + > = UnionToIntersection>>; + + type UnboxBehaviorsData< + Behaviors extends Array | string> + > = UnionToIntersection>>; + + type UnboxBehaviorsProps< + Behaviors extends Array | string> + > = UnionToIntersection>>; + // CombinedInstance models the `this`, i.e. instance type for (user defined) component type CombinedInstance< - Instance extends Component, + Instance extends Component, Data, Methods, - Props - > = Methods & Instance; + Props, + Behaviors extends Array | string> + > = Methods & Instance & UnboxBehaviorsMethods; type Prop = (() => T) | { new (...args: any[]): T & object }; @@ -3773,13 +3804,14 @@ declare namespace wx { unlinked?: (target: Component) => void; } type ThisTypedComponentOptionsWithRecordProps< - V extends Component, + V extends Component, Data, Methods, - Props + Props, + Behaviors extends Array | string> > = object & - ComponentOptions & - ThisType>>; + ComponentOptions & + ThisType, Behaviors>>; interface ComponentRelation { /** 目标组件的相对关系,可选的值为 parent 、 child 、 ancestor 、 descendant */ @@ -3836,10 +3868,11 @@ declare namespace wx { * Component组件参数 */ interface ComponentOptions< - Instance extends Component, + Instance extends Component, Data = DefaultData, Methods = DefaultMethods, - Props = PropsDefinition + Props = PropsDefinition, + Behaviors extends Array | string> = [] > extends Partial { /** * 组件的对外属性,是属性名到属性设置的映射表 @@ -3892,7 +3925,7 @@ declare namespace wx { * 类似于mixins和traits的组件间代码复用机制 * 参见 [behaviors](https://mp.weixin.qq.com/debug/wxadoc/dev/framework/custom-component/behaviors.html) */ - behaviors?: string[]; + behaviors?: Behaviors; /** * 组件生命周期声明对象,组件的生命周期:created、attached、ready、moved、detached将收归到lifetimes字段内进行声明, @@ -3932,7 +3965,7 @@ declare namespace wx { /** * Component实例方法 */ - interface Component { + interface Component | string> = []> { /** * 组件的文件路径 */ @@ -3948,12 +3981,20 @@ declare namespace wx { /** * 组件数据,包括内部数据和属性值 */ - data: D & { [key in keyof P]: PropValueType }; + data: D & UnboxBehaviorsData & { + [key in keyof (P & UnboxBehaviorsProps)]: PropValueType< + (P & UnboxBehaviorsProps)[key] + > + }; /** * 组件数据,包括内部数据和属性值(与 data 一致) */ - properties: D & { [key in keyof P]: PropValueType }; + properties: D & UnboxBehaviorsData & { + [key in keyof (P & UnboxBehaviorsProps)]: PropValueType< + (P & UnboxBehaviorsProps)[key] + > + }; /** * 将数据从逻辑层发送到视图层,同时改变对应的 this.data 的值 * 1. 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。 @@ -4356,12 +4397,13 @@ declare function App( declare function getApp(): wx.App; // #endregion // #region Compontent组件 -declare function Component( +declare function Component | string> = []>( options?: wx.ThisTypedComponentOptionsWithRecordProps< - wx.Component, + wx.Component, D, M, - P + P, + B > ): string; /** @@ -4372,14 +4414,15 @@ declare function Component( * 每个组件可以引用多个 behavior * behavior 也可以引用其他 behavior */ -declare function Behavior( +declare function Behavior | string> = []>( options?: wx.ThisTypedComponentOptionsWithRecordProps< - wx.Component, + wx.Component, D, M, - P + P, + B > -): string; +): wx.Behavior, P & wx.UnboxBehaviorsProps, M & wx.UnboxBehaviorsMethods>; // #endregion // #region Page /** diff --git a/types/weixin-app/weixin-app-tests.ts b/types/weixin-app/weixin-app-tests.ts index 4a344127e7..d6265f3798 100644 --- a/types/weixin-app/weixin-app-tests.ts +++ b/types/weixin-app/weixin-app-tests.ts @@ -8,8 +8,25 @@ interface MyOwnEvent } > {} -let behavior = Behavior({ - behaviors: [], +const parentBehavior = Behavior({ + behaviors: ["wx://form-field"], + properties: { + myParentBehaviorProperty: { + type: String + } + }, + data: { + myParentBehaviorData: "", + }, + methods: { + myParentBehaviorMethod(input: number) { + const s: string = this.data.myParentBehaviorData; + } + } +}); + +const behavior = Behavior({ + behaviors: [parentBehavior, "wx://form-field"], properties: { myBehaviorProperty: { type: String @@ -20,7 +37,7 @@ let behavior = Behavior({ }, attached() {}, methods: { - myBehaviorMethod() { + myBehaviorMethod(input: number) { const s: string = this.data.myBehaviorData; } } @@ -102,6 +119,14 @@ Component({ detached() {}, methods: { + testBehaviors() { + console.log(this.data.myBehaviorData); + console.log(this.data.myBehaviorProperty); + this.myBehaviorMethod(123); + console.log(this.data.myParentBehaviorData); + console.log(this.data.myParentBehaviorProperty); + this.myParentBehaviorMethod(456); + }, readMyDataAndMyProps() { const stringValue1: string = this.data.myProperty; const stringValue2: string = this.data.myProperty2;