diff --git a/src/Ecs/Data.ts b/src/Ecs/Data.ts index 2443ba4..eadc634 100644 --- a/src/Ecs/Data.ts +++ b/src/Ecs/Data.ts @@ -19,10 +19,22 @@ export type Store = (T & HasGeneration)[]; export type SparseStore = Record; export class Data { entity: Store = []; - - [name: string]: Store<{}> | SparseStore<{}>; } +// Ergonomic Lookup typings +type StoreKeysOf = { + [K in keyof DATA]: DATA[K] extends Record ? K : never; +}; +type StoreKeys = StoreKeysOf[keyof DATA]; +type ItemType = S extends Record ? T : never; +type StoreType = K extends keyof DATA ? ItemType : never; +type StoreTypes = { + [I in keyof K]: StoreType; +}; +type MaybeStoreTypes = { + [I in keyof K]: StoreType | null; +}; + /** * Create an entity in the store * @param data store @@ -31,7 +43,7 @@ export class Data { * @returns the new entity's ID and generation */ type Assigner = { - [S in keyof DATA]?: Pick> + [S in StoreKeys]?: StoreType }; export function Create(data: DATA, assign: Assigner, state = Liveness.ALIVE): Id { const entities = data.entity; @@ -57,7 +69,8 @@ export function Create(data: DATA, assign: Assigner, st }; for(const key in assign) { - data[key][freeId] = {...(assign[key] as {}), generation}; + const store = data[key as keyof Data] as Store<{}>|SparseStore<{}>; + store[freeId] = {...(assign as Record)[key] as {}, generation}; } return [freeId, generation]; @@ -76,16 +89,6 @@ export function Remove(data: DATA, [id, generation]: Id, stat } } -// Ergonomic Lookup typings -type ItemType = S extends Record ? T : never; -type StoreType = K extends keyof DATA ? ItemType : never; -type StoreTypes = { - [I in keyof K]: StoreType; -}; -type MaybeStoreTypes = { - [I in keyof K]: StoreType | null; -}; - /** * Look up components that may or may not exist for an entity * @param data store @@ -93,12 +96,13 @@ type MaybeStoreTypes = { * @param components names of components to look for * @returns the cooresponding components, with unfound ones replaced by nulls */ -export function Lookup(data: DATA, [id, generation]: Id, ...components: K): MaybeStoreTypes { +export function Lookup[]>(data: DATA, [id, generation]: Id, ...components: K): MaybeStoreTypes { const entity = data.entity[id]; // inactive entities are fine to lookup, but dead ones are not if(entity && entity.generation == generation && entity.alive != Liveness.DEAD) { return components.map(storeName => { - const component = data[storeName][id]; + const store = data[storeName] as unknown as Store<{}>|SparseStore<{}>; + const component = store[id]; if(component && component.generation == generation) { return component; } else { @@ -113,32 +117,32 @@ export function Lookup(data: DATA, // Ergonomic Join typings export function Join< DATA extends Data, - A extends keyof DATA, + A extends StoreKeys, > ( data: DATA, a: A, ): [ Id, - DATA[A][number] + StoreType & {} ][]; export function Join< DATA extends Data, - A extends keyof DATA, - B extends keyof DATA, + A extends StoreKeys, + B extends StoreKeys, > ( data: DATA, a: A, b: B, ): [ Id, - DATA[A][number], - DATA[B][number] + StoreType & {}, + StoreType & {}, ][]; export function Join< DATA extends Data, - A extends keyof DATA, - B extends keyof DATA, - C extends keyof DATA, + A extends StoreKeys, + B extends StoreKeys, + C extends StoreKeys, > ( data: DATA, a: A, @@ -146,16 +150,16 @@ export function Join< c: C, ): [ Id, - DATA[A][number], - DATA[B][number], - DATA[C][number] + StoreType & {}, + StoreType & {}, + StoreType & {}, ][]; export function Join< DATA extends Data, - A extends keyof DATA, - B extends keyof DATA, - C extends keyof DATA, - D extends keyof DATA, + A extends StoreKeys, + B extends StoreKeys, + C extends StoreKeys, + D extends StoreKeys, > ( data: DATA, a: A, @@ -164,18 +168,18 @@ export function Join< d: D, ): [ Id, - DATA[A][number], - DATA[B][number], - DATA[C][number], - DATA[D][number] + StoreType & {}, + StoreType & {}, + StoreType & {}, + StoreType & {}, ][]; /** * Query a Data collection for all Alive entities possessing the named set of Components. * @returns an array of tuples containing the matching entity [ID, generation]s & associated Components */ -export function Join(data: DATA, ...components: K[]): [Id, ...{}[]][] { +export function Join[]>(data: DATA, ...components: K): [Id, ...{}[]][] { const entities = data.entity; - const stores: (Store<{}>|SparseStore<{}>)[] = components.map(name => data[name]); + const stores = components.map(name => data[name] as unknown as (Store<{}>|SparseStore<{}>)); const results: [Id, ...{}[]][] = []; const firstStore = stores[0];