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

如何在NestJS模块中高效实现Mongoose鉴别器类型推断?

NestJS + Mongoose鉴别器类型推断问题

我正在开发一个NestJS模块,旨在通过Mongoose的鉴别器(discriminators)将各类通知存储在同一张表中。为简化代码并完全依赖TypeScript的类型推断,我刻意避免使用as关键字,但在实现所需的类型收窄和推断时遇到了阻碍。尽管Mongoose的类型设计看似完备,我仍无法让类型推断按预期工作,希望能获得管理鉴别器类型的有效指导。

核心代码示例

import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { HydratedDocument, Model, Types } from 'mongoose';
import {
  ISampleAssignedNotification,
  ITowLogChangeNotification,
  TNotification,
} from './notification.type';
import { Notification } from './schema/notification.schema';

@Injectable()
export class NotificationService {
  constructor(
    @InjectModel(Notification.name)
    private notificationModel: Model<TNotification>,
    @InjectModel('TowLogChange')
    private towLogChangeModel: Model<ITowLogChangeNotification>,
    @InjectModel('SampleAssigned')
    private sampleAssignedModel: Model<ISampleAssignedNotification>,
  ) {}

  async testA() {
    const doc = await this.createA({
      userId: new Types.ObjectId(),
      type: 'TowLogChange',
      metadata: {
        towId: new Types.ObjectId(),
        newStatus: 'some status',
      },
    } as ITowLogChangeNotification);
    console.log(doc.metadata.towId);
  }

  async createA<T extends TNotification>(notification: T) {
    return this.notificationModel.create(notification) as Promise<
      HydratedDocument<T>
    >;
  }

  async testB() {
    const doc = await this.createB({
      userId: new Types.ObjectId(),
      type: 'TowLogChange',
      metadata: {
        towId: new Types.ObjectId(),
        newStatus: 'some status',
      },
    } as ITowLogChangeNotification);

    // towId 无法被类型识别
    // console.log(doc.metadata.towId);

    // 写法过于繁琐,类型无法像testA那样自动推断
    console.log(
      (doc as HydratedDocument<ITowLogChangeNotification>).metadata.towId,
    );
  }

  async createB<T extends TNotification>(notification: T) {
    if (notification.type == 'TowLogChange') {
      return this.towLogChangeModel.create(notification);
    } else if (notification.type == 'SampleAssigned') {
      return this.sampleAssignedModel.create(notification);
    }

    throw new Error('Unpredictable logic place.');
  }
}

简化问题复现

type TLetterA = 'a';
type TLetterB = 'b';

type TLetters = TLetterA | TLetterB;

const letterA: TLetterA = 'a';
const letterB: TLetterB = 'b';
const letterAorB: TLetters = letterA;

function passLetter<T extends TLetters>(letter: T): T {
    if (letter == 'a') {
        return letter
    } else if (letter == 'b') {
        return letter;
    }

    throw new Error('Some error....');
}

const passLetterA = passLetter(letterA);
//   ^? 期望类型为TLetterA,但实际推断为TLetters

内容的提问来源于stack exchange,提问作者Victor Shelepen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 00:45:15