I admit I have not read the full thread, but there’s another topic that seems relevant and I want to link it here:
Hey maucejo, if your colors value is read-only and always the same regardless of the template parameters, you can expose it as a global variable in your template file, for example:
// template.typ
#let colors = (primary: red, secondary: blue)
// main.typ
#import "template.typ": colors, template
#show: template.with(...) // does not affect 'colors'
The colors are #colors.primary and #colors.secondary
However, if the value of colors depends on the parameters specified by the template, then yo…
As I said, I only skimmed this discussion, but I think the solutions presented there match what you and Andrew have come up with, so hopefully that gives you more confidence in your approach.
gasche:
My impression remains that something is missing in the Typst ecosystem, either in the language-level feature of modules/packaged (which should allow parametrization), or at least in community conventions that encourage a packaging style that allows configuration. Returning a dictionary of functions instead of a module seems to be the best approach (for global, read-only configuration parameters), it should be more common and documented clearly somewhere.
I think there is a language-level feature missing, and I’m getting more convinced that it’s a dynamic way of creating modules: Explicit module syntax · Issue #4853 · typst/typst · GitHub That issue links to a few other relevant issues. Particularly on point is this comment :
PgBiel:
I had an idea in a Discord thread which might be relevant to share here. One possibility is to have inline module syntax, meaning you can return a module from a function, and use this for “init”-style functions. For example, you could have
// package/lib.typ
#let init(a: 5, b: 6) = module {
// declarations automatically exported
// much like top-level modules and files
let adder() = a + b
let subber() = a - b
// just like files, modules can have content
// when omitted, the content part is empty / `none`
[Optional content]
}
Then, in your document:
#import "package": init
#import init(a: 10, b: 10): adder, subber
#adder() // 20
#subber() // 0
That would be a great solution for situations where configuration happens once, as opposed to situations where the configuration is contextual, in which case custom types would be superior.
1 Like