NFT Collection (one smart contract) with multiple base URIs (`ERC1155URIStorage`)

I'm a developer, and I am planning to have an NFT collection with different token classes, which will result to different base URIs (I'm using IPFS with NFT.storage as pinning service). Let's say I have 3 token classes -- humans, aliens and monsters. I'll be minting the human NFTs first, maybe 5,000 of them. After a week or so, I'll be minting 3,000 alien NFTs, and then after some time as well, I'll be minting 2,000 monster NFTs.

If I use OpenZeppelin's basic implementation of ERC1155, I can only use one URI for all, differentiated only by {id}. However, I don't think having one URI is possible if I'm minting the different classes separately. If I use ERC1155URIStorage and set the token URI of each, minting cost (i.e., gas fee used for minting) would shoot up.

How do I customize ERC1155URIStorage (or maybe create a new storage solution) such that it allows me to have multiple base URIs (not necessarily 3) without having to spend too much gas on minting?

Visualization:
Human NFT URIs:

ipfs://cidsoierosudfksdjfks/1
ipfs://cidsoierosudfksdjfks/2
ipfs://cidsoierosudfksdjfks/3
...
ipfs://cidsoierosudfksdjfks/5000

Alien NFT URIs:

ipfs://aklsdufoiaueiot/5001
ipfs://aklsdufoiaueiot/5002
ipfs://aklsdufoiaueiot/5003
...
ipfs://aklsdufoiaueiot/8000

Monster NFT URIs:

ipfs://asyr9qyweihsifn/8001
ipfs://asyr9qyweihsifn/8002
ipfs://asyr9qyweihsifn/8003
...
ipfs://asyr9qyweihsifn/10000

Great question. You will want to write your custom override of the URI logic. It might look something like this:

    mapping (uint256 => string) classUris;

    function uri(uint256 id) public view override returns (string memory) {
        uint256 tokenClass = _getTokenClass(id);
        return classUris[tokenClass];
    }

Or you could avoid using storage and hardcode the strings in the code like this:

    function uri(uint256 id) public view override returns (string memory) {
        uint256 tokenClass = _getTokenClass(id);
        if (tokenClass == ALIEN) {
            return "ipfs://.../{id}";
        } else if ...
    }