Issue
I look for creating an Entity type (possibly using conditional types) which generates a property if it does not exist:
type EntityIdType = number | string
type EntityWithId = {
id: EntityIdType
}
type EntityWithoutId = {}
export type EntityMap<E> = {
[id: EntityIdType]: E;
}
class EntityTable<E extends Entity> {
byId: EntityMap<E> = {}
insert = (entity: Entity): EntityIdType => {
const id = ... // I only got it using entity.hasOwnProperty(), sure there is a better way
this.byId[id] = entity
return id
}
get = (id: EntityIdType): Entity => {
this.byId[id] // I only got it comparing with undefined and using 'as'
}
}
const tableWithId = new EntityTable<EntityWithId>()
tableWithId.insert({ id: 'myId', foo: 'bar' })
console.log(tableWithId.get('myId')) // { id: 'myId', foo: 'bar' }
const tableWithoutId = new EntityTable<EntityWithoutId>()
const id = tableWithoutId.insert({ foo: 'bar2' })
console.log(tableWithoutId.get(id)) // { id: 3244, foo: 'bar' }
My almost working (does not insert id
in EntityWithoutId
) but not quite good code for Entity
and EntityTable
:
type Entity<T extends EntityIdType | undefined> = T extends EntityIdType
? EntityWithId
: EntityWithoutId
export class EntityTable<E extends Entity<EntityIdType | undefined>> {
private static autoIncrementId = new AutoIncrementId()
byId: EntityMap<E> = {}
allIds: EntityIdType[] = []
insert = (entity: E): EntityIdType => {
const id = entity.hasOwnProperty('id') ? (entity as EntityWithId).id : EntityTable.autoIncrementId.new()
this.byId[id] = entity
this.allIds.push(id)
return id
}
getByEntityId = (id: EntityIdType): Entity<EntityIdType> | undefined =>
this.byId[id] === undefined ? undefined
: this.byId[id] as Entity<EntityIdType>
}
Solution
Your main problem was that you were not adding the id to your entity after generating it. Here is a slightly less verbose version of your EntityTable.
class EntityTable<Entity extends { id?: EntityIdType }> {
private static autoIncrementId = new AutoIncrementId()
byId: EntityMap<Entity & { id: EntityIdType}> = {}
allIds: EntityIdType[] = []
insert = (entity: Entity): EntityIdType => {
const id = entity.id || EntityTable.autoIncrementId.new()
this.byId[id] = { ...entity, id }
this.allIds.push(id)
return id
}
get = (id: EntityIdType) => this.byId[id]
}
Answered By – ScarpMetal
Answer Checked By – Clifford M. (BugsFixing Volunteer)