diff --git a/packages/calendar/components/month/index.ts b/packages/calendar/components/month/index.ts
index e965d109..5256888c 100644
--- a/packages/calendar/components/month/index.ts
+++ b/packages/calendar/components/month/index.ts
@@ -33,13 +33,13 @@ VantComponent({
       observer: 'setDays',
     },
     showMark: Boolean,
-    rowHeight: [Number, String],
+    rowHeight: null,
     formatter: {
       type: null,
       observer: 'setDays',
     },
     currentDate: {
-      type: [null, Array],
+      type: null,
       observer: 'setDays',
     },
     allowSameDay: Boolean,
@@ -49,7 +49,7 @@ VantComponent({
 
   data: {
     visible: true,
-    days: [],
+    days: [] as Day[],
   },
 
   methods: {
diff --git a/packages/calendar/index.ts b/packages/calendar/index.ts
index 3052f2fc..eb7e8bdb 100644
--- a/packages/calendar/index.ts
+++ b/packages/calendar/index.ts
@@ -37,7 +37,7 @@ VantComponent({
     },
     rangePrompt: String,
     defaultDate: {
-      type: [Number, Array],
+      type: null,
       observer(val) {
         this.setData({ currentDate: val });
         this.scrollIntoView();
@@ -67,7 +67,7 @@ VantComponent({
       value: 'bottom',
     },
     rowHeight: {
-      type: [Number, String],
+      type: null,
       value: ROW_HEIGHT,
     },
     round: {
@@ -103,14 +103,14 @@ VantComponent({
       value: true,
     },
     maxRange: {
-      type: [Number, String],
+      type: null,
       value: null,
     },
   },
 
   data: {
     subtitle: '',
-    currentDate: null,
+    currentDate: null as any,
     scrollIntoView: '',
   },
 
diff --git a/packages/checkbox-group/index.ts b/packages/checkbox-group/index.ts
index 90a41a7c..83814411 100644
--- a/packages/checkbox-group/index.ts
+++ b/packages/checkbox-group/index.ts
@@ -1,3 +1,4 @@
+import { useChildren } from '../common/relation';
 import { VantComponent } from '../common/component';
 
 type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
@@ -5,14 +6,9 @@ type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
 VantComponent({
   field: true,
 
-  relation: {
-    name: 'checkbox',
-    type: 'descendant',
-    current: 'checkbox-group',
-    linked(target) {
-      this.updateChild(target);
-    },
-  },
+  relation: useChildren('checkbox', function (target) {
+    this.updateChild(target);
+  }),
 
   props: {
     max: Number,
@@ -28,9 +24,7 @@ VantComponent({
 
   methods: {
     updateChildren() {
-      (this.children || []).forEach((child: TrivialInstance) =>
-        this.updateChild(child)
-      );
+      this.children.forEach((child) => this.updateChild(child));
     },
 
     updateChild(child: TrivialInstance) {
diff --git a/packages/checkbox/index.ts b/packages/checkbox/index.ts
index 3bad083a..92bb8d70 100644
--- a/packages/checkbox/index.ts
+++ b/packages/checkbox/index.ts
@@ -1,3 +1,4 @@
+import { useParent } from '../common/relation';
 import { VantComponent } from '../common/component';
 
 function emit(
@@ -11,11 +12,7 @@ function emit(
 VantComponent({
   field: true,
 
-  relation: {
-    name: 'checkbox-group',
-    type: 'ancestor',
-    current: 'checkbox',
-  },
+  relation: useParent('checkbox-group'),
 
   classes: ['icon-class', 'label-class'],
 
diff --git a/packages/circle/index.ts b/packages/circle/index.ts
index c412f3d2..a9b20182 100644
--- a/packages/circle/index.ts
+++ b/packages/circle/index.ts
@@ -40,7 +40,7 @@ VantComponent({
       value: WHITE,
     },
     color: {
-      type: [String, Object],
+      type: null,
       value: BLUE,
       observer() {
         this.setHoverColor().then(() => {
diff --git a/packages/col/index.ts b/packages/col/index.ts
index b5d66072..bbddcf83 100644
--- a/packages/col/index.ts
+++ b/packages/col/index.ts
@@ -1,11 +1,8 @@
+import { useParent } from '../common/relation';
 import { VantComponent } from '../common/component';
 
 VantComponent({
-  relation: {
-    name: 'row',
-    type: 'ancestor',
-    current: 'col',
-  },
+  relation: useParent('row'),
 
   props: {
     span: Number,
diff --git a/packages/collapse-item/index.ts b/packages/collapse-item/index.ts
index a9608139..2fb500ec 100644
--- a/packages/collapse-item/index.ts
+++ b/packages/collapse-item/index.ts
@@ -1,14 +1,11 @@
 import { VantComponent } from '../common/component';
+import { useParent } from '../common/relation';
 import { setContentAnimate } from './animate';
 
 VantComponent({
   classes: ['title-class', 'content-class'],
 
-  relation: {
-    name: 'collapse',
-    type: 'ancestor',
-    current: 'collapse-item',
-  },
+  relation: useParent('collapse'),
 
   props: {
     name: null,
diff --git a/packages/collapse/index.ts b/packages/collapse/index.ts
index 1e4199bf..576cd931 100644
--- a/packages/collapse/index.ts
+++ b/packages/collapse/index.ts
@@ -1,11 +1,8 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 
 VantComponent({
-  relation: {
-    name: 'collapse-item',
-    type: 'descendant',
-    current: 'collapse',
-  },
+  relation: useChildren('collapse-item'),
 
   props: {
     value: {
@@ -24,11 +21,9 @@ VantComponent({
 
   methods: {
     updateExpanded() {
-      this.children.forEach(
-        (child: WechatMiniprogram.Component.TrivialInstance) => {
-          child.updateExpanded();
-        }
-      );
+      this.children.forEach((child) => {
+        child.updateExpanded();
+      });
     },
 
     switch(name: string | number, expanded: boolean) {
diff --git a/packages/common/component.ts b/packages/common/component.ts
index 9179fb05..7de3d9a1 100644
--- a/packages/common/component.ts
+++ b/packages/common/component.ts
@@ -1,33 +1,5 @@
 import { basic } from '../mixins/basic';
-import {
-  VantComponentOptions,
-  CombinedComponentInstance,
-} from 'definitions/index';
-
-const relationFunctions = {
-  ancestor: {
-    linked(parent) {
-      // @ts-ignore
-      this.parent = parent;
-    },
-    unlinked() {
-      // @ts-ignore
-      this.parent = null;
-    },
-  },
-  descendant: {
-    linked(child) {
-      // @ts-ignore
-      this.children = this.children || [];
-      // @ts-ignore
-      this.children.push(child);
-    },
-    unlinked(child) {
-      // @ts-ignore
-      this.children = (this.children || []).filter((it) => it !== child);
-    },
-  },
-};
+import { VantComponentOptions } from 'definitions/index';
 
 function mapKeys(source: object, target: object, map: object) {
   Object.keys(map).forEach((key) => {
@@ -37,46 +9,12 @@ function mapKeys(source: object, target: object, map: object) {
   });
 }
 
-function makeRelation(options, vantOptions, relation) {
-  const { type, name, linked, unlinked, linkChanged } = relation;
-  const { beforeCreate, destroyed } = vantOptions;
-  if (type === 'descendant') {
-    options.created = function () {
-      beforeCreate && beforeCreate.bind(this)();
-      this.children = this.children || [];
-    };
-    options.detached = function () {
-      this.children = [];
-      destroyed && destroyed.bind(this)();
-    };
-  }
-  options.relations = Object.assign(options.relations || {}, {
-    [`../${name}/index`]: {
-      type,
-      linked(node) {
-        relationFunctions[type].linked.bind(this)(node);
-        linked && linked.bind(this)(node);
-      },
-      linkChanged(node) {
-        linkChanged && linkChanged.bind(this)(node);
-      },
-      unlinked(node) {
-        relationFunctions[type].unlinked.bind(this)(node);
-        unlinked && unlinked.bind(this)(node);
-      },
-    },
-  });
-}
-
-function VantComponent<Data, Props, Methods>(
-  vantOptions: VantComponentOptions<
-    Data,
-    Props,
-    Methods,
-    CombinedComponentInstance<Data, Props, Methods>
-  > = {}
-): void {
-  const options: any = {};
+function VantComponent<
+  Data extends WechatMiniprogram.Component.DataOption,
+  Props extends WechatMiniprogram.Component.PropertyOption,
+  Methods extends WechatMiniprogram.Component.MethodOption
+>(vantOptions: VantComponentOptions<Data, Props, Methods>): void {
+  const options: WechatMiniprogram.Component.Options<Data, Props, Methods> = {};
 
   mapKeys(vantOptions, options, {
     data: 'data',
@@ -86,16 +24,10 @@ function VantComponent<Data, Props, Methods>(
     beforeCreate: 'created',
     created: 'attached',
     mounted: 'ready',
-    relations: 'relations',
     destroyed: 'detached',
     classes: 'externalClasses',
   });
 
-  const { relation } = vantOptions;
-  if (relation) {
-    makeRelation(options, vantOptions, relation);
-  }
-
   // add default externalClasses
   options.externalClasses = options.externalClasses || [];
   options.externalClasses.push('custom-class');
@@ -104,20 +36,18 @@ function VantComponent<Data, Props, Methods>(
   options.behaviors = options.behaviors || [];
   options.behaviors.push(basic);
 
+  // add relations
+  const { relation } = vantOptions;
+  if (relation) {
+    options.relations = relation.relations;
+    options.behaviors.push(relation.mixin);
+  }
+
   // map field to form-field behavior
   if (vantOptions.field) {
     options.behaviors.push('wx://form-field');
   }
 
-  if (options.properties) {
-    Object.keys(options.properties).forEach((name) => {
-      if (Array.isArray(options.properties[name])) {
-        // miniprogram do not allow multi type
-        options.properties[name] = null;
-      }
-    });
-  }
-
   // add default options
   options.options = {
     multipleSlots: true,
diff --git a/packages/common/relation.ts b/packages/common/relation.ts
new file mode 100644
index 00000000..618dca2d
--- /dev/null
+++ b/packages/common/relation.ts
@@ -0,0 +1,71 @@
+type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
+type RelationOption = WechatMiniprogram.Component.RelationOption;
+
+export function useParent(
+  name: string,
+  onEffect?: (this: TrivialInstance) => void
+) {
+  const path = `../${name}/index`;
+
+  return {
+    relations: {
+      [path]: {
+        type: 'ancestor',
+        linked(this: TrivialInstance) {
+          onEffect && onEffect.call(this);
+        },
+        linkChanged(this: TrivialInstance) {
+          onEffect && onEffect.call(this);
+        },
+        unlinked(this: TrivialInstance) {
+          onEffect && onEffect.call(this);
+        },
+      } as RelationOption,
+    },
+
+    mixin: Behavior({
+      created() {
+        Object.defineProperty(this, 'parent', {
+          get: () => this.getRelationNodes(path)[0],
+        });
+
+        Object.defineProperty(this, 'index', {
+          // @ts-ignore
+          get: () => this.parent?.children?.indexOf(this),
+        });
+      },
+    }),
+  };
+}
+
+export function useChildren(
+  name: string,
+  onEffect?: (this: TrivialInstance, target: TrivialInstance) => void
+) {
+  const path = `../${name}/index`;
+
+  return {
+    relations: {
+      [path]: {
+        type: 'descendant',
+        linked(this: TrivialInstance, target) {
+          onEffect && onEffect.call(this, target);
+        },
+        linkChanged(this: TrivialInstance, target) {
+          onEffect && onEffect.call(this, target);
+        },
+        unlinked(this: TrivialInstance, target) {
+          onEffect && onEffect.call(this, target);
+        },
+      } as RelationOption,
+    },
+
+    mixin: Behavior({
+      created() {
+        Object.defineProperty(this, 'children', {
+          get: () => this.getRelationNodes(path) || [],
+        });
+      },
+    }),
+  };
+}
diff --git a/packages/common/utils.ts b/packages/common/utils.ts
index 2656c7fe..dc6dc0ea 100644
--- a/packages/common/utils.ts
+++ b/packages/common/utils.ts
@@ -113,3 +113,8 @@ export function toPromise(promiseLike: Promise<unknown> | unknown) {
 
   return Promise.resolve(promiseLike);
 }
+
+export function getCurrentPage<T>() {
+  const pages = getCurrentPages();
+  return pages[pages.length - 1] as T & WechatMiniprogram.Page.TrivialInstance;
+}
diff --git a/packages/definitions/index.ts b/packages/definitions/index.ts
index f7087a27..873a1da9 100644
--- a/packages/definitions/index.ts
+++ b/packages/definitions/index.ts
@@ -1,32 +1,45 @@
-import { Weapp } from './weapp';
+interface VantComponentInstance {
+  parent: WechatMiniprogram.Component.TrivialInstance;
+  children: WechatMiniprogram.Component.TrivialInstance[];
+  index: number;
+  $emit: (
+    name: string,
+    detail?: unknown,
+    options?: WechatMiniprogram.Component.TriggerEventOption
+  ) => void;
+}
 
-type RecordToAny<T> = { [K in keyof T]: any };
-
-export type CombinedComponentInstance<Data, Props, Methods> = Methods &
-  WechatMiniprogram.Component.TrivialInstance &
-  Weapp.FormField & {
-    data: Data & RecordToAny<Props>;
-  };
-
-export interface VantComponentOptions<Data, Props, Methods, Instance> {
+export type VantComponentOptions<
+  Data extends WechatMiniprogram.Component.DataOption,
+  Props extends WechatMiniprogram.Component.PropertyOption,
+  Methods extends WechatMiniprogram.Component.MethodOption
+> = {
   data?: Data;
   field?: boolean;
   classes?: string[];
   mixins?: string[];
-  props?: Props & Weapp.PropertyOption;
-  relation?: Weapp.RelationOption<Instance> & {
-    type: 'ancestor' | 'descendant';
-    name: string;
-    current: string;
+  props?: Props;
+  relation?: {
+    relations: Record<string, WechatMiniprogram.Component.RelationOption>;
+    mixin: string;
   };
-  relations?: {
-    [componentName: string]: Weapp.RelationOption<Instance>;
-  };
-  methods?: Methods & Weapp.MethodOption<Instance>;
+
+  methods?: Methods;
 
   // lifetimes
-  beforeCreate?: (this: Instance) => void;
-  created?: (this: Instance) => void;
-  mounted?: (this: Instance) => void;
-  destroyed?: (this: Instance) => void;
-}
+  beforeCreate?: () => void;
+  created?: () => void;
+  mounted?: () => void;
+  destroyed?: () => void;
+} & ThisType<
+  VantComponentInstance &
+    WechatMiniprogram.Component.Instance<
+      Data & {
+        name: string;
+        value: any;
+      },
+      Props,
+      Methods
+    > &
+    Record<string, any>
+>;
diff --git a/packages/definitions/weapp.ts b/packages/definitions/weapp.ts
deleted file mode 100644
index 1363e992..00000000
--- a/packages/definitions/weapp.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-// eslint-disable-next-line @typescript-eslint/no-namespace
-export namespace Weapp {
-  export interface FormField {
-    data: {
-      name: string;
-      value: any;
-    };
-  }
-
-  /**
-   * relation定义,miniprogram-api-typings缺少this定义
-   */
-  export interface RelationOption<Instance> {
-    /** 目标组件的相对关系 */
-    type: 'parent' | 'child' | 'ancestor' | 'descendant';
-    /** 关系生命周期函数,当关系被建立在页面节点树中时触发,触发时机在组件attached生命周期之后 */
-    linked?(
-      this: Instance,
-      target: WechatMiniprogram.Component.TrivialInstance
-    ): void;
-    /** 关系生命周期函数,当关系在页面节点树中发生改变时触发,触发时机在组件moved生命周期之后 */
-    linkChanged?(
-      this: Instance,
-      target: WechatMiniprogram.Component.TrivialInstance
-    ): void;
-    /** 关系生命周期函数,当关系脱离页面节点树时触发,触发时机在组件detached生命周期之后 */
-    unlinked?(
-      this: Instance,
-      target: WechatMiniprogram.Component.TrivialInstance
-    ): void;
-    /** 如果这一项被设置,则它表示关联的目标节点所应具有的behavior,所有拥有这一behavior的组件节点都会被关联 */
-    target?: string;
-  }
-
-  /**
-   * obverser定义,miniprogram-api-typings缺少this定义
-   */
-  type Observer<Instance, T> = (
-    this: Instance,
-    newVal: T,
-    oldVal: T,
-    changedPath: Array<string | number>
-  ) => void;
-
-  /**
-   * methods定义,miniprogram-api-typings缺少this定义
-   */
-  export interface MethodOption<Instance> {
-    [name: string]: (this: Instance, ...args: any[]) => any;
-  }
-
-  export interface ComputedOption<Instance> {
-    [name: string]: (this: Instance) => any;
-  }
-
-  type PropertyType =
-    | StringConstructor
-    | NumberConstructor
-    | BooleanConstructor
-    | ArrayConstructor
-    | ObjectConstructor
-    | FunctionConstructor
-    | null;
-
-  export interface PropertyOption {
-    [name: string]:
-      | PropertyType
-      | PropertyType[]
-      | {
-          /** 属性类型 */
-          type: PropertyType | PropertyType[];
-          /** 属性初始值 */
-          value?: any;
-          /** 属性值被更改时的响应函数 */
-          observer?:
-            | string
-            | Observer<WechatMiniprogram.Component.TrivialInstance, any>;
-          /** 属性的类型(可以指定多个) */
-          optionalTypes?: PropertyType[];
-        };
-  }
-}
diff --git a/packages/dialog/index.ts b/packages/dialog/index.ts
index bd27755d..9787134d 100644
--- a/packages/dialog/index.ts
+++ b/packages/dialog/index.ts
@@ -72,6 +72,10 @@ VantComponent({
       confirm: false,
       cancel: false,
     },
+    callback: ((() => {}) as unknown) as (
+      action: string,
+      context: WechatMiniprogram.Component.TrivialInstance
+    ) => {},
   },
 
   methods: {
diff --git a/packages/dropdown-item/index.ts b/packages/dropdown-item/index.ts
index b93bfd53..dea3213d 100644
--- a/packages/dropdown-item/index.ts
+++ b/packages/dropdown-item/index.ts
@@ -1,17 +1,13 @@
+import { useParent } from '../common/relation';
 import { VantComponent } from '../common/component';
 import { Option } from './shared';
 
 VantComponent({
   field: true,
 
-  relation: {
-    name: 'dropdown-menu',
-    type: 'ancestor',
-    current: 'dropdown-item',
-    linked() {
-      this.updateDataFromParent();
-    },
-  },
+  relation: useParent('dropdown-menu', function () {
+    this.updateDataFromParent();
+  }),
 
   props: {
     value: {
@@ -45,7 +41,7 @@ VantComponent({
   methods: {
     rerender() {
       wx.nextTick(() => {
-        this.parent && this.parent.updateItemListData();
+        this.parent?.updateItemListData();
       });
     },
 
@@ -118,7 +114,7 @@ VantComponent({
       });
 
       if (show) {
-        this.parent.getChildWrapperStyle().then((wrapperStyle: string) => {
+        this.parent?.getChildWrapperStyle().then((wrapperStyle: string) => {
           this.setData({ wrapperStyle, showWrapper: true });
           this.rerender();
         });
diff --git a/packages/dropdown-menu/index.ts b/packages/dropdown-menu/index.ts
index d37e2f8d..110699ef 100644
--- a/packages/dropdown-menu/index.ts
+++ b/packages/dropdown-menu/index.ts
@@ -1,23 +1,15 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 import { addUnit, getRect, getSystemInfoSync } from '../common/utils';
 
-type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
-let ARRAY: TrivialInstance[] = [];
+let ARRAY: WechatMiniprogram.Component.TrivialInstance[] = [];
 
 VantComponent({
   field: true,
 
-  relation: {
-    name: 'dropdown-item',
-    type: 'descendant',
-    current: 'dropdown-menu',
-    linked() {
-      this.updateItemListData();
-    },
-    unlinked() {
-      this.updateItemListData();
-    },
-  },
+  relation: useChildren('dropdown-item', function () {
+    this.updateItemListData();
+  }),
 
   props: {
     activeColor: {
@@ -55,7 +47,7 @@ VantComponent({
   },
 
   data: {
-    itemListData: [],
+    itemListData: [] as Record<string, unknown>[],
   },
 
   beforeCreate() {
@@ -71,18 +63,18 @@ VantComponent({
   methods: {
     updateItemListData() {
       this.setData({
-        itemListData: this.children.map((child: TrivialInstance) => child.data),
+        itemListData: this.children.map((child) => child.data),
       });
     },
 
     updateChildrenData() {
-      this.children.forEach((child: TrivialInstance) => {
+      this.children.forEach((child) => {
         child.updateDataFromParent();
       });
     },
 
     toggleItem(active: number) {
-      this.children.forEach((item: TrivialInstance, index: number) => {
+      this.children.forEach((item, index) => {
         const { showPopup } = item.data;
         if (index === active) {
           item.toggle();
@@ -93,7 +85,7 @@ VantComponent({
     },
 
     close() {
-      this.children.forEach((child: TrivialInstance) => {
+      this.children.forEach((child) => {
         child.toggle(false, { immediate: true });
       });
     },
diff --git a/packages/field/index.ts b/packages/field/index.ts
index f7991443..883d0bda 100644
--- a/packages/field/index.ts
+++ b/packages/field/index.ts
@@ -18,7 +18,7 @@ VantComponent({
     isLink: Boolean,
     leftIcon: String,
     rightIcon: String,
-    autosize: [Boolean, Object],
+    autosize: null,
     required: Boolean,
     iconClass: String,
     clickable: Boolean,
diff --git a/packages/goods-action-button/index.ts b/packages/goods-action-button/index.ts
index 517ff005..883ab99e 100644
--- a/packages/goods-action-button/index.ts
+++ b/packages/goods-action-button/index.ts
@@ -1,15 +1,14 @@
 import { VantComponent } from '../common/component';
-import { link } from '../mixins/link';
+import { useParent } from '../common/relation';
 import { button } from '../mixins/button';
+import { link } from '../mixins/link';
 import { openType } from '../mixins/open-type';
 
 VantComponent({
   mixins: [link, button, openType],
-  relation: {
-    type: 'ancestor',
-    name: 'goods-action',
-    current: 'goods-action-button',
-  },
+
+  relation: useParent('goods-action'),
+
   props: {
     text: String,
     color: String,
@@ -33,12 +32,12 @@ VantComponent({
         return;
       }
 
+      const { index } = this;
       const { children = [] } = this.parent;
-      const { length } = children;
-      const index = children.indexOf(this);
+
       this.setData({
         isFirst: index === 0,
-        isLast: index === length - 1,
+        isLast: index === children.length - 1,
       });
     },
   },
diff --git a/packages/goods-action/index.ts b/packages/goods-action/index.ts
index acb6cb4f..b3cca432 100644
--- a/packages/goods-action/index.ts
+++ b/packages/goods-action/index.ts
@@ -1,36 +1,17 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 
 VantComponent({
-  relation: {
-    type: 'descendant',
-    name: 'goods-action-button',
-    current: 'goods-action',
-    linked() {
-      this.updateStyle();
-    },
-    unlinked() {
-      this.updateStyle();
-    },
-    linkChanged() {
-      this.updateStyle();
-    },
-  },
+  relation: useChildren('goods-action-button', function () {
+    this.children.forEach((item) => {
+      item.updateStyle();
+    });
+  }),
+
   props: {
     safeAreaInsetBottom: {
       type: Boolean,
       value: true,
     },
   },
-
-  methods: {
-    updateStyle() {
-      wx.nextTick(() => {
-        this.children.forEach(
-          (child: WechatMiniprogram.Component.TrivialInstance) => {
-            child.updateStyle();
-          }
-        );
-      });
-    },
-  },
 });
diff --git a/packages/grid-item/index.ts b/packages/grid-item/index.ts
index 4754b18b..fb96a0f6 100644
--- a/packages/grid-item/index.ts
+++ b/packages/grid-item/index.ts
@@ -1,12 +1,9 @@
-import { link } from '../mixins/link';
 import { VantComponent } from '../common/component';
+import { useParent } from '../common/relation';
+import { link } from '../mixins/link';
 
 VantComponent({
-  relation: {
-    name: 'grid',
-    type: 'ancestor',
-    current: 'grid-item',
-  },
+  relation: useParent('grid'),
 
   classes: ['content-class', 'icon-class', 'text-class'],
 
diff --git a/packages/grid/index.ts b/packages/grid/index.ts
index 4c898f02..c45bcfc5 100644
--- a/packages/grid/index.ts
+++ b/packages/grid/index.ts
@@ -1,11 +1,8 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 
 VantComponent({
-  relation: {
-    name: 'grid-item',
-    type: 'descendant',
-    current: 'grid',
-  },
+  relation: useChildren('grid-item'),
 
   props: {
     square: {
@@ -13,7 +10,7 @@ VantComponent({
       observer: 'updateChildren',
     },
     gutter: {
-      type: [Number, String],
+      type: null,
       value: 0,
       observer: 'updateChildren',
     },
@@ -48,11 +45,9 @@ VantComponent({
 
   methods: {
     updateChildren() {
-      this.children.forEach(
-        (child: WechatMiniprogram.Component.TrivialInstance) => {
-          child.updateStyle();
-        }
-      );
+      this.children.forEach((child) => {
+        child.updateStyle();
+      });
     },
   },
 });
diff --git a/packages/index-anchor/index.ts b/packages/index-anchor/index.ts
index f768cc20..24b7b596 100644
--- a/packages/index-anchor/index.ts
+++ b/packages/index-anchor/index.ts
@@ -1,12 +1,9 @@
 import { getRect } from '../common/utils';
 import { VantComponent } from '../common/component';
+import { useParent } from '../common/relation';
 
 VantComponent({
-  relation: {
-    name: 'index-bar',
-    type: 'ancestor',
-    current: 'index-anchor',
-  },
+  relation: useParent('index-bar'),
 
   props: {
     useSlot: Boolean,
diff --git a/packages/index-bar/index.ts b/packages/index-bar/index.ts
index 40bbc1ae..c7b623e0 100644
--- a/packages/index-bar/index.ts
+++ b/packages/index-bar/index.ts
@@ -1,5 +1,6 @@
 import { GREEN } from '../common/color';
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 import { getRect } from '../common/utils';
 import { pageScrollMixin } from '../mixins/page-scroll';
 
@@ -15,17 +16,9 @@ const indexList = () => {
 };
 
 VantComponent({
-  relation: {
-    name: 'index-anchor',
-    type: 'descendant',
-    current: 'index-bar',
-    linked() {
-      this.updateData();
-    },
-    unlinked() {
-      this.updateData();
-    },
-  },
+  relation: useChildren('index-anchor', function () {
+    this.updateData();
+  }),
 
   props: {
     sticky: {
@@ -95,14 +88,13 @@ VantComponent({
 
     setAnchorsRect() {
       return Promise.all(
-        this.children.map(
-          (anchor: WechatMiniprogram.Component.TrivialInstance) =>
-            getRect(anchor, '.van-index-anchor-wrapper').then((rect) => {
-              Object.assign(anchor, {
-                height: rect.height,
-                top: rect.top + this.scrollTop,
-              });
-            })
+        this.children.map((anchor) =>
+          getRect(anchor, '.van-index-anchor-wrapper').then((rect) => {
+            Object.assign(anchor, {
+              height: rect.height,
+              top: rect.top + this.scrollTop,
+            });
+          })
         )
       );
     },
@@ -287,8 +279,7 @@ VantComponent({
       this.scrollToAnchorIndex = index;
 
       const anchor = this.children.find(
-        (item: WechatMiniprogram.Component.TrivialInstance) =>
-          item.data.index === this.data.indexList[index]
+        (item) => item.data.index === this.data.indexList[index]
       );
 
       if (anchor) {
diff --git a/packages/mixins/basic.ts b/packages/mixins/basic.ts
index db152be4..850f99ff 100644
--- a/packages/mixins/basic.ts
+++ b/packages/mixins/basic.ts
@@ -3,13 +3,13 @@ export const basic = Behavior({
     $emit(
       name: string,
       detail?: Record<string, unknown>,
-      options?: Record<string, unknown>
+      options?: WechatMiniprogram.Component.TriggerEventOption
     ) {
       this.triggerEvent(name, detail, options);
     },
 
-    set(data: object, callback: () => void) {
-      this.setData(data, callback);
+    set(data: Record<string, unknown>) {
+      this.setData(data);
 
       return new Promise((resolve) => wx.nextTick(resolve));
     },
diff --git a/packages/mixins/page-scroll.ts b/packages/mixins/page-scroll.ts
index 8d12a1a0..0dfb0018 100644
--- a/packages/mixins/page-scroll.ts
+++ b/packages/mixins/page-scroll.ts
@@ -1,19 +1,15 @@
+import { getCurrentPage } from '../common/utils';
+
 type IPageScrollOption = WechatMiniprogram.Page.IPageScrollOption;
 type Scroller = (
   this: WechatMiniprogram.Component.TrivialInstance,
   event?: IPageScrollOption
 ) => void;
-type TrivialInstance = WechatMiniprogram.Page.TrivialInstance & {
-  vanPageScroller?: Scroller[];
-};
-
-function getCurrentPage(): TrivialInstance {
-  const pages = getCurrentPages();
-  return pages[pages.length - 1] || ({} as TrivialInstance);
-}
 
 function onPageScroll(event?: IPageScrollOption) {
-  const { vanPageScroller = [] } = getCurrentPage();
+  const { vanPageScroller = [] } = getCurrentPage<{
+    vanPageScroller: Scroller[];
+  }>();
 
   vanPageScroller.forEach((scroller: Scroller) => {
     if (typeof scroller === 'function') {
@@ -26,7 +22,7 @@ function onPageScroll(event?: IPageScrollOption) {
 export const pageScrollMixin = (scroller: Scroller) =>
   Behavior({
     attached() {
-      const page = getCurrentPage();
+      const page = getCurrentPage<{ vanPageScroller: Scroller[] }>();
 
       if (Array.isArray(page.vanPageScroller)) {
         page.vanPageScroller.push(scroller.bind(this));
@@ -41,9 +37,8 @@ export const pageScrollMixin = (scroller: Scroller) =>
     },
 
     detached() {
-      const page = getCurrentPage();
-      page.vanPageScroller = (page.vanPageScroller || []).filter(
-        (item) => item !== scroller
-      );
+      const page = getCurrentPage<{ vanPageScroller: Scroller[] }>();
+      page.vanPageScroller =
+        page.vanPageScroller?.filter((item) => item !== scroller) || [];
     },
   });
diff --git a/packages/notify/index.ts b/packages/notify/index.ts
index 6534d086..3c4e98c0 100644
--- a/packages/notify/index.ts
+++ b/packages/notify/index.ts
@@ -31,6 +31,9 @@ VantComponent({
 
   data: {
     show: false,
+    onOpened: (null as unknown) as () => void,
+    onClose: (null as unknown) as () => void,
+    onClick: (null as unknown) as (detail: Record<string, null>) => void,
   },
 
   created() {
diff --git a/packages/notify/index.wxs b/packages/notify/index.wxs
index 3b427521..bbb94c28 100644
--- a/packages/notify/index.wxs
+++ b/packages/notify/index.wxs
@@ -1,5 +1,6 @@
 /* eslint-disable */
 var style = require('../wxs/style.wxs');
+var addUnit = require('../wxs/add-unit.wxs');
 
 function rootStyle(data) {
   return style({
diff --git a/packages/picker/index.ts b/packages/picker/index.ts
index 755349fc..af34a62d 100644
--- a/packages/picker/index.ts
+++ b/packages/picker/index.ts
@@ -151,13 +151,11 @@ VantComponent({
 
     // get values of all columns
     getValues() {
-      return this.children.map(
-        (child: WechatMiniprogram.Component.TrivialInstance) => child.getValue()
-      );
+      return this.children.map((child) => child.getValue());
     },
 
     // set values of all columns
-    setValues(values: []) {
+    setValues(values: any[]) {
       const stack = values.map((value, index) =>
         this.setColumnValue(index, value)
       );
@@ -166,10 +164,7 @@ VantComponent({
 
     // get indexes of all columns
     getIndexes() {
-      return this.children.map(
-        (child: WechatMiniprogram.Component.TrivialInstance) =>
-          child.data.currentIndex
-      );
+      return this.children.map((child) => child.data.currentIndex);
     },
 
     // set indexes of all columns
diff --git a/packages/radio-group/index.ts b/packages/radio-group/index.ts
index 3e60b4bb..9fa1aa38 100644
--- a/packages/radio-group/index.ts
+++ b/packages/radio-group/index.ts
@@ -1,16 +1,12 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 
 VantComponent({
   field: true,
 
-  relation: {
-    name: 'radio',
-    type: 'descendant',
-    current: 'radio-group',
-    linked(target) {
-      this.updateChild(target);
-    },
-  },
+  relation: useChildren('radio', function (target) {
+    this.updateChild(target);
+  }),
 
   props: {
     value: {
diff --git a/packages/radio/index.ts b/packages/radio/index.ts
index a096c7fc..03fcae32 100644
--- a/packages/radio/index.ts
+++ b/packages/radio/index.ts
@@ -1,13 +1,10 @@
 import { VantComponent } from '../common/component';
+import { useParent } from '../common/relation';
 
 VantComponent({
   field: true,
 
-  relation: {
-    name: 'radio-group',
-    type: 'ancestor',
-    current: 'radio',
-  },
+  relation: useParent('radio-group'),
 
   classes: ['icon-class', 'label-class'],
 
diff --git a/packages/rate/index.ts b/packages/rate/index.ts
index 6c062eb5..0b86bb27 100644
--- a/packages/rate/index.ts
+++ b/packages/rate/index.ts
@@ -90,7 +90,7 @@ VantComponent({
         if (target != null) {
           this.onSelect({
             ...event,
-            currentTarget: target,
+            currentTarget: (target as unknown) as WechatMiniprogram.Target,
           });
         }
       });
diff --git a/packages/row/index.ts b/packages/row/index.ts
index f765c815..78beae8c 100644
--- a/packages/row/index.ts
+++ b/packages/row/index.ts
@@ -1,18 +1,14 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 
 VantComponent({
-  relation: {
-    name: 'col',
-    type: 'descendant',
-    current: 'row',
-    linked(target) {
-      const { gutter } = this.data;
+  relation: useChildren('col', function (target) {
+    const { gutter } = this.data;
 
-      if (gutter) {
-        target.setData({ gutter });
-      }
-    },
-  },
+    if (gutter) {
+      target.setData({ gutter });
+    }
+  }),
 
   props: {
     gutter: {
@@ -23,8 +19,8 @@ VantComponent({
 
   methods: {
     setGutter() {
-      this.getRelationNodes('../col/index').forEach((col) => {
-        col.setData(this.data.gutter);
+      this.children.forEach((col) => {
+        col.setData(this.data);
       });
     },
   },
diff --git a/packages/sidebar-item/index.ts b/packages/sidebar-item/index.ts
index a4dfdf3a..44c0e2da 100644
--- a/packages/sidebar-item/index.ts
+++ b/packages/sidebar-item/index.ts
@@ -1,13 +1,10 @@
 import { VantComponent } from '../common/component';
+import { useParent } from '../common/relation';
 
 VantComponent({
   classes: ['active-class', 'disabled-class'],
 
-  relation: {
-    type: 'ancestor',
-    name: 'sidebar',
-    current: 'sidebar-item',
-  },
+  relation: useParent('sidebar'),
 
   props: {
     dot: Boolean,
diff --git a/packages/sidebar/index.ts b/packages/sidebar/index.ts
index 4a92653e..4fd08974 100644
--- a/packages/sidebar/index.ts
+++ b/packages/sidebar/index.ts
@@ -1,17 +1,10 @@
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
 
 VantComponent({
-  relation: {
-    name: 'sidebar-item',
-    type: 'descendant',
-    current: 'sidebar',
-    linked() {
-      this.setActive(this.data.activeKey);
-    },
-    unlinked() {
-      this.setActive(this.data.activeKey);
-    },
-  },
+  relation: useChildren('sidebar-item', function () {
+    this.setActive(this.data.activeKey);
+  }),
 
   props: {
     activeKey: {
diff --git a/packages/stepper/index.ts b/packages/stepper/index.ts
index 4b3dc85e..7d68c41e 100644
--- a/packages/stepper/index.ts
+++ b/packages/stepper/index.ts
@@ -39,7 +39,7 @@ VantComponent({
     disableInput: Boolean,
     decimalLength: {
       type: Number,
-      value: null,
+      value: (null as unknown) as number,
       observer: 'check',
     },
     min: {
diff --git a/packages/sticky/index.ts b/packages/sticky/index.ts
index 6859ddde..e6fad06e 100644
--- a/packages/sticky/index.ts
+++ b/packages/sticky/index.ts
@@ -122,8 +122,8 @@ VantComponent({
     getContainerRect() {
       const nodesRef: WechatMiniprogram.NodesRef = this.data.container();
 
-      return new Promise((resolve) =>
-        nodesRef.boundingClientRect(resolve).exec()
+      return new Promise<WechatMiniprogram.BoundingClientRectCallbackResult>(
+        (resolve) => nodesRef.boundingClientRect(resolve).exec()
       );
     },
   },
diff --git a/packages/swipe-cell/index.ts b/packages/swipe-cell/index.ts
index 8856dc21..0d04b3b7 100644
--- a/packages/swipe-cell/index.ts
+++ b/packages/swipe-cell/index.ts
@@ -28,7 +28,7 @@ VantComponent({
     },
     asyncClose: Boolean,
     name: {
-      type: [Number, String],
+      type: null,
       value: '',
     },
   },
diff --git a/packages/tab/index.ts b/packages/tab/index.ts
index aee716ba..8a784cc3 100644
--- a/packages/tab/index.ts
+++ b/packages/tab/index.ts
@@ -1,11 +1,8 @@
+import { useParent } from '../common/relation';
 import { VantComponent } from '../common/component';
 
 VantComponent({
-  relation: {
-    name: 'tabs',
-    type: 'ancestor',
-    current: 'tab',
-  },
+  relation: useParent('tabs'),
 
   props: {
     dot: {
@@ -29,7 +26,7 @@ VantComponent({
       observer: 'update',
     },
     name: {
-      type: [Number, String],
+      type: null,
       value: '',
     },
   },
diff --git a/packages/tabbar-item/index.ts b/packages/tabbar-item/index.ts
index 84b67bb7..552b080e 100644
--- a/packages/tabbar-item/index.ts
+++ b/packages/tabbar-item/index.ts
@@ -1,4 +1,5 @@
 import { VantComponent } from '../common/component';
+import { useParent } from '../common/relation';
 
 VantComponent({
   props: {
@@ -12,14 +13,12 @@ VantComponent({
     },
   },
 
-  relation: {
-    name: 'tabbar',
-    type: 'ancestor',
-    current: 'tabbar-item',
-  },
+  relation: useParent('tabbar'),
 
   data: {
     active: false,
+    activeColor: '',
+    inactiveColor: '',
   },
 
   methods: {
diff --git a/packages/tabbar/index.ts b/packages/tabbar/index.ts
index 6c003617..3697e4c2 100644
--- a/packages/tabbar/index.ts
+++ b/packages/tabbar/index.ts
@@ -1,21 +1,13 @@
-import { getRect } from '../common/utils';
 import { VantComponent } from '../common/component';
+import { useChildren } from '../common/relation';
+import { getRect } from '../common/utils';
 
 type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
 
 VantComponent({
-  relation: {
-    name: 'tabbar-item',
-    type: 'descendant',
-    current: 'tabbar',
-    linked(target) {
-      target.parent = this;
-      target.updateFromParent();
-    },
-    unlinked() {
-      this.updateChildren();
-    },
-  },
+  relation: useChildren('tabbar-item', function () {
+    this.updateChildren();
+  }),
 
   props: {
     active: {
diff --git a/packages/tabs/index.ts b/packages/tabs/index.ts
index c7e3f1ad..af2eee02 100644
--- a/packages/tabs/index.ts
+++ b/packages/tabs/index.ts
@@ -8,6 +8,7 @@ import {
   requestAnimationFrame,
 } from '../common/utils';
 import { isDef } from '../common/validator';
+import { useChildren } from '../common/relation';
 
 type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
 
@@ -16,24 +17,9 @@ VantComponent({
 
   classes: ['nav-class', 'tab-class', 'tab-active-class', 'line-class'],
 
-  relation: {
-    name: 'tab',
-    type: 'descendant',
-    current: 'tabs',
-    linked(target) {
-      target.index = this.children.length - 1;
-      this.updateTabs();
-    },
-    unlinked() {
-      this.children = this.children.map(
-        (child: TrivialInstance, index: number) => {
-          child.index = index;
-          return child;
-        }
-      );
-      this.updateTabs();
-    },
-  },
+  relation: useChildren('tab', function () {
+    this.updateTabs();
+  }),
 
   props: {
     sticky: Boolean,
@@ -45,22 +31,22 @@ VantComponent({
     animated: {
       type: Boolean,
       observer() {
-        this.children.forEach((child: TrivialInstance, index: number) =>
+        this.children.forEach((child, index) =>
           child.updateRender(index === this.data.currentIndex, this)
         );
       },
     },
     lineWidth: {
-      type: [String, Number],
+      type: null,
       value: 40,
       observer: 'resize',
     },
     lineHeight: {
-      type: [String, Number],
+      type: null,
       value: -1,
     },
     active: {
-      type: [String, Number],
+      type: null,
       value: 0,
       observer(name) {
         if (name !== this.getCurrentName()) {
@@ -108,7 +94,7 @@ VantComponent({
     scrollLeft: 0,
     scrollable: false,
     currentIndex: 0,
-    container: null,
+    container: (null as unknown) as () => WechatMiniprogram.NodesRef,
     skipTransition: true,
     lineOffsetLeft: 0,
   },
diff --git a/packages/tree-select/index.ts b/packages/tree-select/index.ts
index 2532003a..ff46fdaa 100644
--- a/packages/tree-select/index.ts
+++ b/packages/tree-select/index.ts
@@ -22,7 +22,7 @@ VantComponent({
       observer: 'updateSubItems',
     },
     height: {
-      type: [Number, String],
+      type: null,
       value: 300,
     },
     max: {
diff --git a/packages/uploader/index.ts b/packages/uploader/index.ts
index 4a66fb39..8adc7f21 100644
--- a/packages/uploader/index.ts
+++ b/packages/uploader/index.ts
@@ -16,7 +16,7 @@ VantComponent({
       value: 80,
     },
     name: {
-      type: [Number, String],
+      type: null,
       value: '',
     },
     accept: {
@@ -65,7 +65,7 @@ VantComponent({
   },
 
   data: {
-    lists: [],
+    lists: [] as File[],
     isInCount: true,
   },
 
@@ -168,7 +168,7 @@ VantComponent({
       if (!this.data.previewFullImage) return;
 
       const { index } = event.currentTarget.dataset;
-      const { lists } = this.data as { lists: File[] };
+      const { lists } = this.data;
       const item = lists[index];
 
       wx.previewImage({
diff --git a/tsconfig.json b/tsconfig.json
index 85836495..b5641810 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -11,8 +11,7 @@
     "lib": ["ESNext"],
     "types": ["miniprogram-api-typings"],
     "paths": {
-      "definitions/*": ["./packages/definitions/*"],
-      "packages/*": ["./packages/*"]
+      "definitions/*": ["./packages/definitions/*"]
     },
     "skipLibCheck": true
   },