#Help with type augmentation

19 messages · Page 1 of 1 (latest)

grave kelp
#

Hello there. I'll keep this as short as possible. I have a "core" project which my games are based off of. This core project has a type called Positions, and it has a similar structure like this:

type Positions = {
    loading: {
        logo: PosConfig,
        progress: PosConfig,
        message: PosConfig
    },
    menu: {
        buttons: {
            playButton: PosConfig,
            customizeButton: PosConfig,
            settings: {
                general: PosConfig,
                user: PosConfig
            }
        }
    },
    main: {
        hud: {
            health: PosConfig,
            stamina: PosConfig,
            stats: {
                distance: PosConfig,
                objective: PosConfig
            }
        }
    }
}

In the core, it loads the data from a JSON file (it follows that format), and I can then access it via other this.game.positions.

Now, the actual game imports the core as a module (since multiple games use the same core), and it provides its own positions and resources. Although all the games follow a similar format, some games might have some special animations or elements which require their own positions. For instance, there might be an extra stat in the main hud, so in the JSON file, I could just list it under main.stats.special. My question is, since I am importing the core from another file, how can I add that property for that specific project? I have tried declaration merging, but that hasn't worked. My attempt was like this:

// types.d.ts
declare module "game-core/src/tools" {
    type Positions = {
        main: {
            hud: {
                stats: {
                    special: PosConfig
                }
            }
        }
    }
}

This just simply did not do anything.

(Continued in the message below due to character limit)

#

I also tried converting Positions into an interface and using an interface instead, but I got an error saying that "main" did not follow the correct structure. This looked like this:

// types.d.ts
declare module "game-core/src/tools" {
    interface Positions {
        main: { // Error here
            hud: {
                stats: {
                    special: PosConfig
                }
            }
        }
    }
}

And that basically led me to nothing. My question is, is it possible to "merge" parts of a type / interface when using declare module, and if so, how? If not, what would be a better approach to this? That is my question. I thank you for your time and help, they are truly appreciated.

next violet
#

Declaration merging (and interface extends in general) does not allow you to deeply merge things.

#

For example this code is just not allowed:

zealous sableBOT
#
interface Foo {
    prop: { a: string }
}

interface Foo {
    prop: { b: string }
//  ^^^^
// Subsequent property declarations must have the same type.  Property 'prop' must be of type '{ a: string; }', but here has type '{ b: string; }'.
}
next violet
#

You have to shallow merge and addition only, so if you want to deeply merge Foo['prop'] you have to make that a separate interface and shallow merge that:

type Foo = {
    prop: Prop
}

interface Prop {
    a: string
}

interface Prop {
    b: string
}
next violet
#

No.

grave kelp
#

What would be the best way to approach my problem then?

#

Because to be fair, making everything a separate interface does not seem like a good solution.

next violet
#

I don't know enough context to give a concrete suggestion, but in general I feel like declaration merging is kind of a niche feature anyways.

#

If Position can be arbitrarily changed, then every code that uses Position has to be written in a way that takes that into account.

grave kelp
#

The overall idea is to have a core which has a preset structure (and the code), and actual games can utilize the core as a package, and if needed, they can extend a specific class to overwrite it.

next violet
#

Ideally whatever extra data would not be a part of Position, so you don't need to declaration merge onto it at all.

grave kelp
#

Say my core has a class for handling loading animations, that class can be extended and overwritten in the game project.

#

And since it is a custom class, it might use special positions, so this.game.positions will not satisfy the new properties.

next violet
#

One way is to have an extra property or something at the root of Position and just declaration merge that.

grave kelp
#

Shame

#

Well, thank you for the help.