如何在Realm不同Schema中复用基础属性并兼容TypeScript?
解决Realm与TypeScript中Schema基础属性复用问题
问题背景
在Realm+TypeScript开发中,定义了包含_id、createdAt、updatedAt的基础SchemaBaseEntitySchema,希望创建子Schema(如SystemSchema)时无需重复声明这些属性,同时保证TypeScript能识别它们。但尝试让BaseEntitySchema继承Realm.Object,再让SystemSchema继承BaseEntitySchema后,调用useQuery(SystemSchema)会报错“Unexpected arguments passed to useQuery”,目前只能重复声明基础属性,寻求更优方案。
基础Schema代码(Base.ts):
import Realm from 'realm'; export type BaseId = Realm.BSON.ObjectId; export interface BaseEntity { id?: BaseId; createdAt: string; updatedAt: string; syncDetails: SyncDetails; // 需确保SyncDetails类型已提前定义 } export class BaseEntitySchema { _id!: Realm.BSON.ObjectId; createdAt!: Date; updatedAt!: Date; static schema: Realm.ObjectSchema = { name: 'BaseEntity', properties: { _id: 'objectId', createdAt: 'date', updatedAt: 'date', }, primaryKey: '_id', }; }
当前子Schema代码(System.ts):
import Realm from 'realm'; import { BaseEntity, BaseEntitySchema } from 'shared/offline-realm/schemas/base'; export interface System extends BaseEntity { name: string; serialNumber: string; locationId: string; corporationId: string; } export class SystemSchema extends Realm.Object<SystemSchema> { name!: string; serialNumber!: string; locationId!: string; corporationId!: string; static schema: Realm.ObjectSchema = { name: 'System', properties: { ...BaseEntitySchema.schema.properties, name: 'string', serialNumber: 'string', locationId: 'string', corporationId: 'string', }, primaryKey: '_id', }; }
最优解决方案
方案1:正确实现类继承(解决useQuery报错)
Realm对类继承有严格规范,错误的继承方式会导致useQuery无法识别Schema。调整BaseEntitySchema为抽象类并正确继承Realm.Object,同时添加泛型约束:
- 修改
Base.ts中的BaseEntitySchema:
import Realm from 'realm'; export type BaseId = Realm.BSON.ObjectId; // 统一接口类型与Schema的Date类型,避免不一致 export interface BaseEntity { id?: BaseId; createdAt: Date; updatedAt: Date; syncDetails: SyncDetails; } // 改为抽象类,添加泛型约束以符合Realm继承要求 export abstract class BaseEntitySchema<T extends BaseEntitySchema<T>> extends Realm.Object<T> { _id!: Realm.BSON.ObjectId; createdAt!: Date; updatedAt!: Date; static schema: Realm.ObjectSchema = { name: 'BaseEntity', properties: { _id: 'objectId', createdAt: 'date', updatedAt: 'date', }, primaryKey: '_id', }; }
- 修改
System.ts中的SystemSchema:
import Realm from 'realm'; import { BaseEntity, BaseEntitySchema } from 'shared/offline-realm/schemas/base'; export interface System extends BaseEntity { name: string; serialNumber: string; locationId: string; corporationId: string; } // 继承BaseEntitySchema并指定自身泛型,同时实现System接口 export class SystemSchema extends BaseEntitySchema<SystemSchema> implements System { name!: string; serialNumber!: string; locationId!: string; corporationId!: string; static schema: Realm.ObjectSchema = { name: 'System', properties: { ...BaseEntitySchema.schema.properties, name: 'string', serialNumber: 'string', locationId: 'string', corporationId: 'string', }, // 复用基础Schema的主键定义 primaryKey: BaseEntitySchema.schema.primaryKey, }; }
关键说明:
- 抽象类避免直接实例化基础Schema
- 泛型约束
T extends BaseEntitySchema<T>符合Realm对继承类的内部要求 - 接口与类的双重约束保证TypeScript类型完全匹配
- 此时
useQuery(SystemSchema)可正常工作,Realm能正确识别继承后的Schema
方案2:使用类型工具自动合并属性(无需类继承)
若不想用类继承,可通过TypeScript类型工具和Schema合并函数,实现属性复用同时保证类型安全:
- 在
Base.ts中添加类型工具:
import Realm from 'realm'; export type BaseId = Realm.BSON.ObjectId; export interface BaseEntity { _id: BaseId; createdAt: Date; updatedAt: Date; syncDetails: SyncDetails; } // 抽离基础属性的Schema定义 export const BaseSchemaProperties: Realm.ObjectSchema['properties'] = { _id: 'objectId', createdAt: 'date', updatedAt: 'date', }; // 自动映射Schema属性对应的TS类型 export type BaseSchemaType = { [K in keyof typeof BaseSchemaProperties]: typeof BaseSchemaProperties[K] extends 'objectId' ? Realm.BSON.ObjectId : typeof BaseSchemaProperties[K] extends 'date' ? Date : never; };
- 在
System.ts中复用:
import Realm from 'realm'; import { BaseEntity, BaseSchemaProperties, BaseSchemaType } from 'shared/offline-realm/schemas/base'; // 合并基础类型与自定义类型 export interface System extends BaseEntity { name: string; serialNumber: string; locationId: string; corporationId: string; } // 类实现合并后的类型,无需手动声明基础属性 export class SystemSchema extends Realm.Object<SystemSchema> implements BaseSchemaType, System { name!: string; serialNumber!: string; locationId!: string; corporationId!: string; static schema: Realm.ObjectSchema = { name: 'System', properties: { ...BaseSchemaProperties, name: 'string', serialNumber: 'string', locationId: 'string', corporationId: 'string', }, primaryKey: '_id', }; }
关键说明:
BaseSchemaType自动映射Schema属性到TS类型,避免手动重复声明- 类实现
BaseSchemaType和System接口,TypeScript会自动推断所有属性 - 对象展开语法合并Schema属性,无需重复编写基础属性定义
常见问题排查
- 若
useQuery仍报错,检查Realm初始化时是否正确注册了子Schema(无需单独注册基础Schema) - 确保接口类型与Schema属性类型完全匹配(比如原代码中
BaseEntity的createdAt为string,但Schema中是date,这种不一致会导致TS类型错误,需统一为Date)
内容的提问来源于stack exchange,提问作者shet_tayyy
相关产品推荐
相关产品推荐

