HandlebarsApplicationMixin Usage from the foundry-vtt-types node package

I have recently started to use foundry to dm my games and as a programmer myself I have been building macros and simple module stuff for the last few weeks. I am newish to type script since I use C++ mostly for my work, so I am a bit lost here. How am I supposed to use HandlebarsApplicationMixin? Every time I try to extend my custom class with HandlebarsApplicationMixin(DocumentSheetV2), I get an error that says no base constructor has the specified number of type arguments. I know C++ knowledge doesn’t transfer directly, but it seems to just be a generic type definition so why would it have a constructor error?
Solution:
You can see the generic parameters for DocumentSheetV2 at its definition: ```ts declare class DocumentSheetV2< Document extends foundry.abstract.Document.Any, RenderContext extends AnyObject = EmptyObject,...
Jump to solution
29 Replies
LukeAbby
LukeAbby2mo ago
Hey, I don't check the #package-development threads as often since usually TypeScript questions go in #typescript. regardless, you're saying that just HandlebarsApplicationMixin(DocumentSheetV2) is giving this error?
1024bits
1024bitsOP2mo ago
Ah that’s my bad I just joined the server and didn’t see that
LukeAbby
LukeAbby2mo ago
not a problem just pointing out that I have #typescript set up to ping me, it's just chance that I saw this so fast by comparison
1024bits
1024bitsOP2mo ago
ESLint is erroring saying “no base constructor has the specified number of type arguments” Using latest version of the master branch btw for the types
LukeAbby
LukeAbby2mo ago
I think you probably mean main but yes main is for v12 beta right now
1024bits
1024bitsOP2mo ago
Right old habits
LukeAbby
LukeAbby2mo ago
so you got the right branch not a problem just wanted to make sure we were talking about the same branch in case you were actually on, idk, actual master somehow (which would be very very old by now) Yeah so the issue is that DocumentV2 requires generic parameters
export default class AmbientLightConfig<
RenderContext extends AnyObject = EmptyObject,
Configuration extends
DocumentSheetV2.Configuration<AmbientLightDocument.ConfiguredInstance> = DocumentSheetV2.Configuration<AmbientLightDocument.ConfiguredInstance>,
RenderOptions extends DocumentSheetV2.RenderOptions = DocumentSheetV2.RenderOptions,
> extends HandlebarsApplicationMixin(DocumentSheetV2)<
AmbientLightDocument.ConfiguredInstance,
RenderContext,
Configuration,
RenderOptions
> {}
export default class AmbientLightConfig<
RenderContext extends AnyObject = EmptyObject,
Configuration extends
DocumentSheetV2.Configuration<AmbientLightDocument.ConfiguredInstance> = DocumentSheetV2.Configuration<AmbientLightDocument.ConfiguredInstance>,
RenderOptions extends DocumentSheetV2.RenderOptions = DocumentSheetV2.RenderOptions,
> extends HandlebarsApplicationMixin(DocumentSheetV2)<
AmbientLightDocument.ConfiguredInstance,
RenderContext,
Configuration,
RenderOptions
> {}
dumb error message, absolutely, but asfik there's no way to make a friendlier error here you can see in this example usage that HandlebarsApplicationMixin(DocumentSheetV2)<...> is written the parameters in the <...> "pass-through" the mixin to DocumentSheetV2
Solution
LukeAbby
LukeAbby2mo ago
You can see the generic parameters for DocumentSheetV2 at its definition:
declare class DocumentSheetV2<
Document extends foundry.abstract.Document.Any,
RenderContext extends AnyObject = EmptyObject,
Configuration extends DocumentSheetV2.Configuration<Document> = DocumentSheetV2.Configuration<Document>,
RenderOptions extends DocumentSheetV2.RenderOptions = DocumentSheetV2.RenderOptions,
> extends ApplicationV2<RenderContext, Configuration, RenderOptions> {
declare class DocumentSheetV2<
Document extends foundry.abstract.Document.Any,
RenderContext extends AnyObject = EmptyObject,
Configuration extends DocumentSheetV2.Configuration<Document> = DocumentSheetV2.Configuration<Document>,
RenderOptions extends DocumentSheetV2.RenderOptions = DocumentSheetV2.RenderOptions,
> extends ApplicationV2<RenderContext, Configuration, RenderOptions> {
1024bits
1024bitsOP2mo ago
Ahhh gotcha thank you so much. Been such a mental pain going from a strongly typed language to this. The fact it is sort of typed makes me think in c++ terms so I keep messing stuff up.
LukeAbby
LukeAbby2mo ago
by most accounts TypeScript is still strongly typed of course its types don't exist at runtime and unfortunately there's a bunch of unsoundness if you want to think about what's going on in C++ terms, we've basically passed a template through a function (though in C++ you can't pass a template to a function so you'd have to make the 'function' a macro or a template itself asfik) since we didn't provide any of the parameters to this template, we still have to provide them somehow hence HandlebarsApplicationMixin(DocumentSheetV2)<...> is basically equivalent to HandlebarsApplicationMixin(DocumentSheetV2<...>)... but this second more intuitive version isn't valid for annoying reasons
1024bits
1024bitsOP2mo ago
Gotcha. Makes a lot more sense now thank you. Though when I put the <…> at the end it errors saying it expected a type lol is that something with my tsconfig maybe?
LukeAbby
LukeAbby2mo ago
can you copy and paste exactly what you're trying to write? like class YourClass extends ... {} with the minimum context required? I don't care what's in the class body itself
1024bits
1024bitsOP2mo ago
export class EffectConfig extends HandlebarsApplicationMixin(DocumentSheetV2)<…> {}
LukeAbby
LukeAbby2mo ago
ah so when I wrote <...> I meant ... as "fill in here" not as a literal syntactic construct
1024bits
1024bitsOP2mo ago
Ahh sorry I misunderstood this as some sort of typescript syntax called “passthrough”
LukeAbby
LukeAbby2mo ago
yeah understandable you can see an example here, DocumentSheetV2 takes 4 generic parameters, Document, RenderContext, Configuration, and RenderOptions most people only care about Document and RenderContext, fortunately Configuration and RenderOptions are optional
1024bits
1024bitsOP2mo ago
Ok thanks that is working fine now.
LukeAbby
LukeAbby2mo ago
RenderContext is what's returned by _prepareContext
/**
* Prepare application rendering context data for a given render request.
* @param options - Options which configure application rendering behavior
* @returns Context data for the render operation
*/
protected _prepareContext(options: DeepPartial<RenderOptions>): Promise<RenderContext>;
/**
* Prepare application rendering context data for a given render request.
* @param options - Options which configure application rendering behavior
* @returns Context data for the render operation
*/
protected _prepareContext(options: DeepPartial<RenderOptions>): Promise<RenderContext>;
Document should hopefully be pretty intuitive
1024bits
1024bitsOP2mo ago
Gotcha I think I’ve seen that in some of the examples online I’ve been looking at. Mostly been learning by looking at other modules, though some are not in typescript so I sorta have to translate it.
LukeAbby
LukeAbby2mo ago
right there are a few systems out there written in TypeScript but we'll have better docs before fvtt-types v12 gets out of beta to explain the original error btw, to get it you have to either be using some complex mixin stuff (what we're doing) or use an archaic way of defining classes:
declare const Foo: {
new <T>(): object;
}

class Bar extends Foo {}
declare const Foo: {
new <T>(): object;
}

class Bar extends Foo {}
you'll get the same error here
No base constructor has the specified number of type arguments.
No base constructor has the specified number of type arguments.
it's fundamentally the same thing as you get with this:
class Foo<T> {}

class Bar extends Foo {}
class Foo<T> {}

class Bar extends Foo {}
but this gives the nicer error Generic type 'Foo<T>' requires 1 type argument(s). in both cases Foo is the "base constructor" because in both cases Foo is a constructor (something you can run new on, so like a class) and "base" because it's what you're trying to extend so it's saying "what you're trying to extend doesn't have the number of arguments you're trying to pass" which in your case was 0 unintuitive for sure!
1024bits
1024bitsOP2mo ago
Hmmm alright. It’ll take some getting used to but I’ve only spent about a week learning all this. Ran a few sessions using some of the already made modules, but I felt a lot of inconsistency in how I actually wanted the game to act so decided it would be better to learn it myself. Hopefully a few more weeks and I won’t be as lost 😂
LukeAbby
LukeAbby2mo ago
haha feel free to pop into #typescript with any questions
1024bits
1024bitsOP2mo ago
Thanks. I’ll mark this as solved when I get back to my computer
LukeAbby
LukeAbby2mo ago
also if you have any areas that aren't built out yet in fvtt-types just let us know I like to prioritise things people are actually using but there's known patterns that don't work yet like xyz.update({ "some.dot.key": 2 })
1024bits
1024bitsOP2mo ago
Gotcha thanks. I’ll definitely reach out if I find something. So far though it is working great
LukeAbby
LukeAbby2mo ago
that's the hope if you run into any "circular errors" which are of the form "... referenced directly or indirectly ..." or "... excessively deep ..." these tend to be the hardest to diagnose yourself and it's only been until recently that I can say there's only 1 of those left in fvtt-types itself
1024bits
1024bitsOP2mo ago
Haha alright I’ll remember that. Sounds comparable to the horrors of segfaults
LukeAbby
LukeAbby2mo ago
at least you get coredumps for that and sanitizers etc.
1024bits
1024bitsOP2mo ago
True
Want results from more Discord servers?
Add your server