I am faced with a field that can either be an ID or have a value, and I am attempting to type this field using TypeScript
import { InferSchemaType, Schema, Types, model } from 'mongoose';
const personSchema = new Schema({
_id: Schema.Types.ObjectId,
name: String,
age: Number,
});
const storySchema = new Schema({
author: { type: Schema.Types.ObjectId, ref: 'Person' },
title: String,
});
export type PersonDao = { _id: Types.ObjectId } & InferSchemaType<typeof personSchema>;
export type StoryDao = { _id: Types.ObjectId; author: Types.ObjectId | PersonDao } & Omit<InferSchemaType<typeof storySchema>, 'author'>;;
export const Person = model('Person', personSchema);
export const Story = model('Story', storySchema);
Story.findOne({ _id: 'fakeId' })
.populate<StoryDao>('author')
.exec()
.then((story: StoryDao) => {
console.log(story.author.name); // error
});
When trying to access the 'name' attribute in the console.log, I encounter this error
Property 'name' does not exist on type 'ObjectId | PersonDao'.
Property 'name' does not exist on type 'ObjectId'.ts(2339)
If I define the type as follows
export type StoryDao = { _id: Types.ObjectId; author: PersonDao } & Omit<InferSchemaType<typeof storySchema>, 'author'>;;
export const story: StoryDao = {
_id: new Types.ObjectId(),
author: new Types.ObjectId(), // error
title: 'fakeTitle',
};
The error regarding 'name' is resolved, but now I face it regarding 'author' when creating a StoryDao object
'ObjectId' is not assignable to type 'PersonDao'.
Type 'ObjectId' is missing the following properties from type '{ createdAt: NativeDate; updatedAt: NativeDate; }': createdAt, updatedAtts(2322)
This appears to be a limitation of TypeScript with unions, as I encounter a similar issue here
type Test = number | { name: string }
const test: Test = {} as Test;
console.log('DEBUG: ', test.name); // error
How would you approach typing this particular field?