小程序
小游戏
企业微信
微信支付
扫描小程序码分享
1、创建一个behavior,并在组件中引入这个behavior,调用behavior里的data和方法 都会报错不存在该属性或者方法;虽然是可以用as any 就可以调用到,但是有没有更好的解决方法呢?
2、在组件中引入这个behavior,调用behavior里的data和方法 都会报错不存在该属性或者方法;
9 个回答
加粗
标红
插入代码
插入链接
插入图片
上传视频
declare namespace WechatMiniprogram.Page { interface ILifetime { test():void; } } declare namespace WechatMiniprogram.Component { interface InstanceMethods<D extends DataOption> { test(): void; } }
可以尝试在类型声明中typings/index.d.ts进行声明类型扩展,应该会有用
你好,麻烦通过点击下方“反馈信息”按钮,提供出现问题的。
我有一个相对来说比较省力,校验完备,但不那么优雅的解决方案。
废话少说,代码如下:
// use.ts function useBehavior<TData extends WechatMiniprogram.Behavior.DataOption, TProperty extends WechatMiniprogram.Behavior.PropertyOption, TMethod extends WechatMiniprogram.Behavior.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = Record<string, never>>(opt: Partial<WechatMiniprogram.Component.Data<TData>> & Partial<WechatMiniprogram.Component.Property<TProperty>> & Partial<WechatMiniprogram.Component.Method<TMethod>> & Partial<WechatMiniprogram.Component.OtherOption> & Partial<WechatMiniprogram.Component.Lifetimes> & ThisType<WechatMiniprogram.Component.Instance<TData, TProperty, TMethod, TCustomInstanceProperty>>) { const behaviorID = Behavior(opt) return { behaviorID, // 仅仅为了方便获取内部变量类型故 _optType: {} as typeof opt, } } export { useBehavior } // detailBehavior.ts import { useBehavior } from "@/utils/use" const { behaviorID, _optType, } = useBehavior({ properties: { detailId: { type: String, value: '' }, }, data: { isDetailLoading: false as boolean, detailLoadError: '', isDetail: false as boolean, }, observers: { 'detailId': function (newDetailId) { if (!newDetailId || this.data.isDetailLoading) { return } this.setData({ isDetailLoading: true, detailLoadError: '', isDetail: true }) const needSetData = {} this.getDetailByDetailId?.(this.data.detailId)?.then()?.catch((err) => { Object.assign(needSetData, { detailLoadError: err.toString() }) })?.finally(() => { Object.assign(needSetData, { isDetailLoading: false }) this.setData(needSetData) }) } }, methods: { getDetailByDetailId(id: number | string) { return Promise.resolve('') } } }) export default behaviorID // 此处已经把当前behavior特有的data(properties)和methods导出来了 export type DetailBehavior = typeof _optType // detail.ts import detailBehavior, { DetailBehavior } from './detailBehavior' import ortherBehavior, { BehaviorOrthers } from './detailBehavior' Component({ behaviors: [detailBehavior, ortherBehavior] data: { anyDataInThisComponent: {}, ...{} as DetailBehavior['data'] & BehaviorOrthers['data'] }, methods: { ...{} as DetailBehavior['methods'] & BehaviorOrthers['methods'] ortherSelfMethod(){ }, } })
我支持楼上不用behavior,而是自己手动展开。behavior这个是普通Object,随意发挥了。
封装一个use方法
export function useSmsBehavior(data: TData){ const smsBehavior = Behavior({ data: { useName: "", }, methods: { test(){ ... } }, ... }); return { data: data as TData & { // add data in behavior useName: string; }, smsBehavior, }; }
使用Behavior
const {smsBehavior, data} = useSmsBehavior({money: 100}); Component({ behaviors: [smsBehavior], properties: {}, data, method: { getMoney(){ console.log(this.data.money, this.data.userName); this.test(); } } }
方法
declare namespace WechatMiniprogram.Page { interface ILifetime { test():void; } } declare namespace WechatMiniprogram.Component { interface InstanceMethods { test(): void; } }
方法的处理可能会污染没有使用behavior的页面。如果不怕麻烦也可以把properties、methods丢进use方法里处理一下。
遇到同样的问题,我的解决方案是弃用了behavior这个功能,将data跟methods封装起来,在Page/Component函数被调用时再添加进去...为了语法上的声明,选择了不用behavior,有点无奈。
// funcs/test.ts export const testData = { test: '' } export const testMethods = { // 但是函数内如果要使用this,就要对this再加上声明 test (this: WechatMiniprogram.Page.Instance<typeof testData, {}>) { // do something this.setData({ test: 'hello world' }) } } // components/x/x.ts import { testData, testMethods } from 'path/to/funcs/test' Component({ data: { ...testData, // other component data }, methods: { ...testMethods, // other component methods } }) // pages/x/x.ts import { testData, testMethods } from 'path/to/funcs/test' Page({ ...testMethods, data: { ...testData, // other page data }, // other page methods })
最后怎么解决的??
同求解……我每次都要 (this as any).test() ,但这样看起来很拉跨
这个恐怕无解。
behavior是通过一个识别符在运行时嵌入的, 然后这个identifier是个string。Typescript的类型推断不可能从这个string里推导出你需要的类型。
能想到的唯一办法就是你自己写一个新的类Component的函数,把behavior的类型作为generic parameter传进去,然后用它来调用原来的Component的并更改相应的类型参数。
还是不够雅致,但这个behavior就是这样设计的。。。
如果不是通过string而是通过object嵌入,或者全部是类React Hooks的函数式编程好多类型推导会方便很多。
遇到同样的问题,求解(typescript)
关注后,可在微信内接收相应的重要提醒。
请使用微信扫描二维码关注 “微信开放社区” 公众号
declare namespace WechatMiniprogram.Page { interface ILifetime { test():void; } } declare namespace WechatMiniprogram.Component { interface InstanceMethods<D extends DataOption> { test(): void; } }
可以尝试在类型声明中typings/index.d.ts进行声明类型扩展,应该会有用
我有一个相对来说比较省力,校验完备,但不那么优雅的解决方案。
废话少说,代码如下:
// use.ts function useBehavior<TData extends WechatMiniprogram.Behavior.DataOption, TProperty extends WechatMiniprogram.Behavior.PropertyOption, TMethod extends WechatMiniprogram.Behavior.MethodOption, TCustomInstanceProperty extends WechatMiniprogram.IAnyObject = Record<string, never>>(opt: Partial<WechatMiniprogram.Component.Data<TData>> & Partial<WechatMiniprogram.Component.Property<TProperty>> & Partial<WechatMiniprogram.Component.Method<TMethod>> & Partial<WechatMiniprogram.Component.OtherOption> & Partial<WechatMiniprogram.Component.Lifetimes> & ThisType<WechatMiniprogram.Component.Instance<TData, TProperty, TMethod, TCustomInstanceProperty>>) { const behaviorID = Behavior(opt) return { behaviorID, // 仅仅为了方便获取内部变量类型故 _optType: {} as typeof opt, } } export { useBehavior } // detailBehavior.ts import { useBehavior } from "@/utils/use" const { behaviorID, _optType, } = useBehavior({ properties: { detailId: { type: String, value: '' }, }, data: { isDetailLoading: false as boolean, detailLoadError: '', isDetail: false as boolean, }, observers: { 'detailId': function (newDetailId) { if (!newDetailId || this.data.isDetailLoading) { return } this.setData({ isDetailLoading: true, detailLoadError: '', isDetail: true }) const needSetData = {} this.getDetailByDetailId?.(this.data.detailId)?.then()?.catch((err) => { Object.assign(needSetData, { detailLoadError: err.toString() }) })?.finally(() => { Object.assign(needSetData, { isDetailLoading: false }) this.setData(needSetData) }) } }, methods: { getDetailByDetailId(id: number | string) { return Promise.resolve('') } } }) export default behaviorID // 此处已经把当前behavior特有的data(properties)和methods导出来了 export type DetailBehavior = typeof _optType // detail.ts import detailBehavior, { DetailBehavior } from './detailBehavior' import ortherBehavior, { BehaviorOrthers } from './detailBehavior' Component({ behaviors: [detailBehavior, ortherBehavior] data: { anyDataInThisComponent: {}, ...{} as DetailBehavior['data'] & BehaviorOrthers['data'] }, methods: { ...{} as DetailBehavior['methods'] & BehaviorOrthers['methods'] ortherSelfMethod(){ }, } })
我支持楼上不用behavior,而是自己手动展开。behavior这个是普通Object,随意发挥了。
封装一个use方法
export function useSmsBehavior(data: TData){ const smsBehavior = Behavior({ data: { useName: "", }, methods: { test(){ ... } }, ... }); return { data: data as TData & { // add data in behavior useName: string; }, smsBehavior, }; }
使用Behavior
const {smsBehavior, data} = useSmsBehavior({money: 100}); Component({ behaviors: [smsBehavior], properties: {}, data, method: { getMoney(){ console.log(this.data.money, this.data.userName); this.test(); } } }
方法
declare namespace WechatMiniprogram.Page { interface ILifetime { test():void; } } declare namespace WechatMiniprogram.Component { interface InstanceMethods { test(): void; } }
方法的处理可能会污染没有使用behavior的页面。如果不怕麻烦也可以把properties、methods丢进use方法里处理一下。
遇到同样的问题,我的解决方案是弃用了behavior这个功能,将data跟methods封装起来,在Page/Component函数被调用时再添加进去...为了语法上的声明,选择了不用behavior,有点无奈。
// funcs/test.ts export const testData = { test: '' } export const testMethods = { // 但是函数内如果要使用this,就要对this再加上声明 test (this: WechatMiniprogram.Page.Instance<typeof testData, {}>) { // do something this.setData({ test: 'hello world' }) } } // components/x/x.ts import { testData, testMethods } from 'path/to/funcs/test' Component({ data: { ...testData, // other component data }, methods: { ...testMethods, // other component methods } }) // pages/x/x.ts import { testData, testMethods } from 'path/to/funcs/test' Page({ ...testMethods, data: { ...testData, // other page data }, // other page methods })
最后怎么解决的??
同求解……我每次都要 (this as any).test() ,但这样看起来很拉跨
这个恐怕无解。
behavior是通过一个识别符在运行时嵌入的, 然后这个identifier是个string。Typescript的类型推断不可能从这个string里推导出你需要的类型。
能想到的唯一办法就是你自己写一个新的类Component的函数,把behavior的类型作为generic parameter传进去,然后用它来调用原来的Component的并更改相应的类型参数。
还是不够雅致,但这个behavior就是这样设计的。。。
如果不是通过string而是通过object嵌入,或者全部是类React Hooks的函数式编程好多类型推导会方便很多。
遇到同样的问题,求解(typescript)