screepers / typed-screeps

Strong TypeScript declarations for the game Screeps.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

store on energy and all resource structures

pbrink231 opened this issue Β· comments

This is probably a more novice question on typescript. How do you deal with a variable that could be a structure like spawn or storage.

Sample code (if available)

    private test(struct: AnyStoreStructure, resource: ResourceConstant) {
        const used = struct.store.getUsedCapacity(resource)
    }

I get this error due to a structure can be an extension which has a store of Store<RESOURCE_ENERGY, false>; and storage which has a store of type StoreDefinition = Store<ResourceConstant, false>

I am getting this error with the above code. I am unsure how to allow this the proper way?

[!] (plugin rpt2) Error: D:/programs/screeps-ts-restart/src/departments/shipping.ts(64,39): semantic error TS2349: This expression is not callable.
  Each member of the union type '(<R extends "energy" | "power" | "ops" | "U" | "L" | "K" | "Z" | "O" | "H" | "X" | "OH" | "ZK" | "UL" | "G" | "UH" | "UO" | "KH" | "KO" | "LH" | "LO" | "ZH" | "ZO" | "GH" | "GO" | "UH2O" | "UHO2" | ... 58 more ... | undefined = undefined>(resource?: R | undefined) => R extends undefined ? null : R extends "energy" ?...' has signatures, but none of those signatures are compatible with each other.
src\departments\shipping.ts
Error: D:/programs/screeps-ts-restart/src/departments/shipping.ts(64,39): semantic error TS2349: This expression is not callable.
  Each member of the union type '(<R extends "energy" | "power" | "ops" | "U" | "L" | "K" | "Z" | "O" | "H" | "X" | "OH" | "ZK" | "UL" | "G" | "UH" | "UO" | "KH" | "KO" | "LH" | "LO" | "ZH" | "ZO" | "GH" | "GO" | "UH2O" | "UHO2" | ... 58 more ... | undefined = undefined>(resource?: R | undefined) => R extends undefined ? null : R extends "energy" ?...' has signatures, but none of those signatures are compatible with each other.

Your Environment

  • "@types/screeps": "^3.1.0",

I am trying to create "universal hauler" that takes energy from mining outposts and dropped resources and deposit it into:

  • spawns
  • extensions
  • links
  • storage
    But I cant figure out how I could treat those structures uniformly. I recieve error exactly like pbrink231.

I am unable to reproduce this. Could someone provide more information?

I'm actually running into this right now, and I think the error lies somewhere within my really poor understanding of types/values/unions.

So the code looks like this:

      const targets = creep.room.find(FIND_STRUCTURES, {
        filter: (structure: AnyStructure) => {
          const freeCapacity: number =
            "store" in structure ? (structure.store.getFreeCapacity(RESOURCE_ENERGY) as number) : -1;
          return freeCapacity > 0;
        }
      })

And the error says:

semantic error TS2349: This expression is not callable.
  Each member of the union type '(<R extends "energy" | "power" | "ops" | "U" | "L" | "K" | "Z" | "O" |
  "H" | "X" | "OH" | "ZK" | "UL" | "G" | "UH" | "UO" | "KH" | "KO" | "LH" | "LO" | "ZH" | "ZO" | "GH" |
  "GO" | "UH2O" | "UHO2" | ... 58 more ... | undefined = undefined>(resource?: R | undefined) =>
  R extends undefined ? number : R extends Resource...' has signatures, but none of those
   signatures are compatible with each other.

The docs mention:

Any place in code that uses a constant (ex STRUCTURE_EXTENSION or FIND_MY_SPAWNS is now constrained to use literal types

And even includes ResourceConstant in the list.. Which appears to be what this function (getFreeCapacity) wants, but that doesn't make sense to me since that could literally be any resource, which would defeat the purpose of passing in a resource type, right?

Also a novice at TypeScript, but really having trouble figuring out what this particular function wants as an argument.

Quick update, it appears this code works... I assume this has to do with what "type" of store is being returned from the "Store" reference on structure?

      const targets = creep.room.find(FIND_STRUCTURES, {
        filter: (structure: AnyStructure): boolean => {
          const freeCapacity: number | null =
            "store" in structure ? (structure.store as GenericStoreBase).getFreeCapacity(RESOURCE_ENERGY) : -1;
          return freeCapacity ? freeCapacity > 0 : false;
        }
      });

@adamtaylor13 Correct. There are certain structures which have stores that can contain any type of resource (ex. Container, Terminal) and then there are structures which have restricted stores (ex. Tower only takes energy). With the current type definitions there just isn't enough info for the compiler to tell which is which if you have them in a mixed array. Also unfortunately it's not smart enough to realize energy may be in both sets.

Casting the store as a GenericStore, as you've done is the generally acknowledged workaround. The other solution would be to first narrow down the structure types into compatible storage. For example, a switch statement testing structure.StructureType where each case captures a set of structures with compatible storage, or do it all 1:1. By testing on structure.structureType TS should be able to identify the type of the structure, and therefore the type of storage.

Screeps is a fun game, and learning TS is a worthy challenge but don't let the structured nature of it stop you from enjoying the game. If something is really getting you stuck, see if casting it to something (like the generic store type), or worst case as any will allow you to keep things moving. Especially since adding 3rd party types to something we can't control can leave a few rough edges.

I highly recommend anyone wanting to play Screeps with TypeScript to join #typescript on the official Discord (recently moved from Slack) https://twitter.com/ScreepsGame/status/1419919747437764612 There is a great community there for TS, other languages, and the game overall.

@pbrink231 @rudykocur Sorry for not getting you this feedback sooner.

@pyrodogg Big thanks for the thoroughly-detailed response! πŸ™ŒπŸ» I actually just joined the discord today and made my foray into TS today. I use TS in my day-to-day work. I'm quite familiar with plain JS, but I'm still pretty fresh with TS, so I'm actually using Screeps as a great opportunity to have a little fun and sharpen my TS intuition. I played for about 3 hours yesterday with just Vanilla JS before joining the discord and venturing into TS πŸ˜…

Anyway, your response coupled with the code I somehow managed to get running makes a lot of sense in hindsight! Thanks again! πŸ™πŸ»

Even using the new code provided i don't get any errors.
Im on typescript version 4.3.5 and @types/screeps version 3.2.3.

Ah, well that could be some of it. I noticed in my package.json (which I bummed off the official TS-starter repo) that the versions are a bit behind what you've got:

{
    "@types/screeps": "^3.1.0",
    "typescript": "^3.8.3"
}

I too started with the starter. but i updated ts. Don't think i updated the types, so it is probably the ts version. Try updating it and see what happens.

Thanks for that reminder as well. With ^3.8.3 npm wouldn't be pulling in any >= 4 version of Typescript. I've just pushed a lint/build dependency update for the starter project.

I suggest updating the ts version and consider this issue "fixed". Assuming that is the cause.