You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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,同时添加泛型约束:

  1. 修改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',
    };
}
  1. 修改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合并函数,实现属性复用同时保证类型安全:

  1. 在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;
};
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 13:16:22