收藏
回答

使用typescript开发behavior,调用data 的数据过不了类型检测怎么办?

1、创建一个behavior,并在组件中引入这个behavior,调用behavior里的data和方法 都会报错不存在该属性或者方法;虽然是可以用as any 就可以调用到,但是有没有更好的解决方法呢?

2、在组件中引入这个behavior,调用behavior里的data和方法 都会报错不存在该属性或者方法;

回答关注问题邀请回答
收藏

11 个回答

  • niniyou
    niniyou
    2022-08-29
    declare namespace WechatMiniprogram.Page {
      interface ILifetime {
        test():void;
      }
    }
    declare namespace WechatMiniprogram.Component {
      interface InstanceMethods<D extends DataOption> {
        test(): void;
      }
    }
    

    可以尝试在类型声明中typings/index.d.ts进行声明类型扩展,应该会有用

    2022-08-29
    有用 2
    回复 1
    • Damon
      Damon
      2023-02-21
      不错
      2023-02-21
      回复
  • 👾👾👾👾👾
    👾👾👾👾👾
    08-22

    2020年的问题,现在2024年了,有什么完美解法吗?

    08-22
    有用 1
    回复 3
    • 李浩然
      李浩然
      08-27
      蹲一下
      08-27
      回复
    • 尹joy
      尹joy
      12-06
      可以看下当前页面我的方案
      12-06
      回复
    • 尹joy
      尹joy
      12-06回复李浩然
      看看我的
      12-06
      回复
  • 不吱
    不吱
    2021-05-27

    同求解……我每次都要 (this as any).test() ,但这样看起来很拉跨

    2021-05-27
    有用 1
    回复
  • 尹joy
    尹joy
    12-05

    只需要定义behavior的同时能自动导出对应的behavior类型,在page或者component的property/data/methods中定义一个空对象并强制类型为behavior对应的property/data/methods类型即可。

    // 组件或者页面的定义文件
    import listBehavior, { type ListBehavior } from '@/behaviors/listBehavior'
    type Item = { id: string; num: number }
    Component({
        behaviors: [listBehavior],
        properties: {
            ...{} as ListBehavior<Item[]>['properties'],
            otherProp: {
                type: String,
                value: '0'
            }
        },
        data: {
            ...{} as ListBehavior<Item[]>['data'],
        },
        methods: {
            ...{} as ListBehavior<Item[]>['methods'],
            getList(page, pageSize) {
                return doReq('/getAllList', page, pageSize)
            }
            onPullDownRefresh() {
                // listBehavior['methods']中的refreshList
                this.refreshList()
            },
            onReachBottom() {
                // listBehavior['methods']中的loadList
                this.loadList()
            }
        }
    })
    


    // behaviors/listBehavior.ts
    import { useBehavior } from '@/utils/use'
    const {
        behaviorID,
        _optType,
    } = useBehavior({
        data: {
            list: [],
            _page: 1,
            _pageSize: 10,
        },
        methods: {
            loadList() {
                // 此处的getList是使用behavior的组件或者页面中定义的
                this.getList(this.data._page, this.data._pageSize).then(res => {
                    this.setData({
                        list: res
                    })
                })
            },
            refreshList() {
                this.setData({
                    _page: 1,
                    list: []
                })
                this.loadList()
            }
        }
    })
    export default behaviorID
    export type ListBehavior = typeof _optType
    


    核心就在于定义behavior的同时能够导出一个能表示当前类型的变量_optType,_optType可以是没有任何实际作用的空对象{},它的作用就是能够通过 typeof 来实现自动导出behavior类型。

    这个解决方案无任何副作用,校验完备,使用简便。

    12-05
    有用
    回复 5
    • 梦游
      梦游
      星期三 11:11
      这个_optType能根据behavior传的参数自动推导出来吗,是说要要自己手写一个空对象然后断言,我看behavior返回的是一个字符串,貌似没办法推导类型了
      星期三 11:11
      回复
    • 尹joy
      尹joy
      星期三 16:16回复梦游
      需要写个工具,导出behavior id标识时导出并断言一个空对象为定义behavior时的data,methods,property等入参。你可以参考我的实现
      星期三 16:16
      1
      回复
    • 梦游
      梦游
      星期四 18:06回复尹joy
      实测发现,method的类型是可选类型,在扩展到页面里直接this.去访问会ts报错可能是undefined,看了一下d.ts里的类型也没问题啊,是怎么回事呢,
      星期四 18:06
      回复
    • 梦游
      梦游
      星期四 18:43回复尹joy
      我把这个method的可选范型改成非空就好了,但是小程序的类型声明文件里确实是可选的
      星期四 18:43
      回复
    • 尹joy
      尹joy
      2天前回复梦游
      你把代码贴全一点,我这边试的都正常,不管是在Component,Page,或是在其他behavior的构造方法里。
      2天前
      回复
  • 李浩然
    李浩然
    08-27

    我修改了类型文件中 `WechatMiniprogram.Page.Constructor` 的和 `Options` 类型的定义. 添加了两个新的可选范型 `BehaviorData` 和 `BehaviorMethods`. 在使用 `Page` 的时候把相应的 behavior 的类型传进去.

    type Options<
      TData extends DataOption,
      TCustom extends CustomOption,
      BehaviorData,
      BehaviorMthods
    > = (TCustom &
      Partial<Data<TData>> &
      Partial<ILifetime> & {
        options?: Component.ComponentOptions
      }) &
      ThisType<Instance<TData & BehaviorData, TCustom & BehaviorMthods>>
    
    
    interface Constructor {
      <TData extends DataOption, TCustom extends CustomOption, BehaviorData = {}, BehaviorMethods = {}>(
        options: Options<TData, TCustom, BehaviorData, BehaviorMethods>
      ): void
    }
    
    Page<TData, TOptions, BehaviorData, BehaviorMethods>({
      behaviors: [behavior],
      ...
    })
    


    暂时可以解决这个问题.

    08-27
    有用
    回复
  • Roger🌌
    Roger🌌
    2023-05-05

    我支持楼上不用behavior,而是自己手动展开。behavior这个是普通Object,随意发挥了。

    2023-05-05
    有用
    回复
  • 晴天
    晴天
    2023-03-15

    封装一个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方法里处理一下。

    2023-03-15
    有用
    回复
  • class.lfz
    class.lfz
    2022-10-19

    遇到同样的问题,我的解决方案是弃用了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
    })
    


    2022-10-19
    有用
    回复
  • 冲鸭
    冲鸭
    2022-07-11

    最后怎么解决的??

    2022-07-11
    有用
    回复
  • 生不可无你
    生不可无你
    2021-03-30

    这个恐怕无解。

    behavior是通过一个识别符在运行时嵌入的, 然后这个identifier是个string。Typescript的类型推断不可能从这个string里推导出你需要的类型。

    能想到的唯一办法就是你自己写一个新的类Component的函数,把behavior的类型作为generic parameter传进去,然后用它来调用原来的Component的并更改相应的类型参数。

    还是不够雅致,但这个behavior就是这样设计的。。。

    如果不是通过string而是通过object嵌入,或者全部是类React Hooks的函数式编程好多类型推导会方便很多。

    2021-03-30
    有用
    回复

正在加载...

登录 后发表内容
问题标签