文档管理中心

@Type装饰器:标记类属性的类型

为了实现序列化类时不丢失属性的复杂类型,开发者可以使用@Type装饰器装饰类属性。

@Type的目的是标记类属性,配合PersistenceV2使用,防止序列化时类型信息丢失。在阅读本文档前,建议提前阅读:PersistenceV2

说明

@Type从API version 12开始支持。

从API version 12开始,该装饰器支持在元服务中使用。

概述

@Type标记类属性,使得类属性序列化时不丢失类型信息,便于类的反序列化。

装饰器说明

展开
@Type装饰器 说明
装饰器参数 type:类型。
可装饰的类型 Object class以及Array、Date、Map、Set等内嵌类型。

使用限制

  1. 只能用在@ObservedV2装饰的类中,不能用在自定义组件中。

    收起
    自动换行
    深色代码主题
    复制
    1. class Sample {
    2. private data: number = 0;
    3. }
    4. @ObservedV2
    5. class Info {
    6. @Type(Sample)
    7. @Trace public sample: Sample = new Sample(); // 正确用法
    8. }
    收起
    自动换行
    深色代码主题
    复制
    1. @Observed
    2. class Info2 {
    3. @Type(Sample)
    4. sample: Sample = new Sample(); // 错误用法,不能用在@Observed装饰的类中,编译时报错
    5. }
    6. @ComponentV2
    7. struct Index {
    8. @Type(Sample)
    9. sample: Sample = new Sample(); // 错误用法,不能用在自定义组件中,编译时报错
    10. build() {
    11. }
    12. }
  2. 不支持collections.Set、collections.Map等类型。

  3. 不支持非built-in类型。如PixelMap、NativePointer等Native类型,以及ArrayList等ArkTS容器类型。

  4. 不支持简单类型。如string、number、boolean等。

  5. 不支持构造函数含参的类。

使用场景

持久化数据

收起
自动换行
深色代码主题
复制
  1. import { PersistenceV2, Type } from '@kit.ArkUI';
  2. @ObservedV2
  3. class SampleChild {
  4. @Trace childNumber: number = 1;
  5. }
  6. @ObservedV2
  7. class Sample {
  8. // 对于复杂对象需要@Type修饰,确保反序列化成功,去掉@Type会反序列化值失败。
  9. @Type(SampleChild)
  10. // 对于没有初值的类属性,经过@Type修饰后,需要手动保存,否则持久化失败。
  11. // 无法使用@Type修饰的类属性,必须要有初值才能持久化。
  12. @Trace sampleChild?: SampleChild = undefined;
  13. }
  14. @Entry
  15. @ComponentV2
  16. struct TestCase {
  17. @Local sample: Sample = PersistenceV2.connect(Sample, () => new Sample)!;
  18. build() {
  19. Column() {
  20. Text('childNumber value:' + this.sample.sampleChild?.childNumber)
  21. .fontSize(30)
  22. .margin(10)
  23. .onClick(() => {
  24. this.sample.sampleChild = new SampleChild();
  25. this.sample.sampleChild.childNumber = 2;
  26. PersistenceV2.save(Sample);
  27. })
  28. }
  29. .width('100%')
  30. }
  31. }

常见问题

@Type传入容器泛型而非元素类型

@Type装饰Array<T>、Set<T>、Map<string, T>等容器类型的属性时,应传入元素类型T对应的类,不应传入Array<T>等容器泛型。泛型参数在运行时会被擦除,@Type(Array<T>)等同于@Type(Array),@Type(Set<T>)等同于@Type(Set),框架无法从中获知元素类型为T。

展开
属性类型 @Type应传入 不应传入
Array<T> T Array<T>、Array
Set<T> T Set<T>、Set
Map<string, T> T Map<string, T>、Map

当T为基本类型、Date、Array、Set、Map等非自定义类时,框架原生支持反序列化,@Type参数不影响结果。当T为自定义类时,首次运行数据可正常保存,但应用重启从磁盘恢复数据时,反序列化创建空容器实例(如new Array())而非new T(),T的构造函数不执行,T的属性未被初始化。反序列化结果取决于T的属性序列化后的值类型:值为基本类型或对象时被隐式转换为undefined,值为数组时打印Error日志,错误码为140107。具体如下:

展开
T的属性类型 序列化后的值 反序列化结果
number、string、boolean 基本类型 隐式转换为undefined,无报错
Date 字符串 隐式转换为undefined,无报错
Array、Set、Map 数组 打印Error日志,错误码为140107
自定义类 对象 隐式转换为undefined,无报错

以下示例中,元素类型ItemModel包含基本类型属性和容器类型属性,使用@Type(Array<ItemModel>)后应用重启将触发上述问题:

收起
自动换行
深色代码主题
复制
  1. import { PersistenceV2, Type } from '@kit.ArkUI';
  2. @ObservedV2
  3. class ItemModel {
  4. @Trace num: number = 1;
  5. @Trace arr: Array<number> = [1, 2, 3];
  6. @Trace set: Set<number> = new Set([1, 2, 3]);
  7. }
  8. @ObservedV2
  9. class Data {
  10. @Type(Array<ItemModel>)
  11. // 错误用法:运行时退化为@Type(Array),传入容器类型而非元素类型
  12. // 反序列化时创建new Array()而非new ItemModel(),ItemModel的构造函数不执行,num、arr、set属性均未初始化
  13. // num序列化后为基本类型,反序列化时被隐式转换为undefined;arr、set序列化后为数组,反序列化时打印Error日志,错误码为140107
  14. // Set<T>、Map<string, T>场景传入@Type(Set<T>)或@Type(Map<string, T>)同理
  15. @Trace items: Array<ItemModel> = new Array();
  16. }
  17. @Entry
  18. @ComponentV2
  19. struct TestCase {
  20. @Local data: Data = PersistenceV2.connect(Data, () => new Data())!;
  21. build() {
  22. Column() {
  23. Button('push and save')
  24. .onClick(() => {
  25. this.data.items.push(new ItemModel());
  26. // 手动持久化数据到磁盘
  27. PersistenceV2.save(Data);
  28. })
  29. }
  30. }
  31. }

上述示例中,首次点击按钮将ItemModel实例存入数组并保存到磁盘后,结束进程,第二次重新启动时,执行反序列化失败,打印如下Error日志:

收起
自动换行
深色代码主题
复制
  1. FIX THIS APPLICATION ERROR: For PersistenceV2 'Data' key has error, error code: 140107, message: The type of target 'undefined' mismatches the type of source 'object'

正确写法是将@Type参数改为元素类型T对应的类,对Array<T>、Set<T>、Map<string, T>均适用:

收起
自动换行
深色代码主题
复制
  1. @ObservedV2
  2. class Data {
  3. @Type(ItemModel) // 正确用法:传入元素类型ItemModel对应的类
  4. @Trace items: Array<ItemModel> = new Array();
  5. }
在 指南 中进行搜索
请输入您想要搜索的关键词