Skip to main content

Undefined variables

At render time, if a template variable or path to a variable can not be resolved to a value, an instance of Undefined is used in its place. We can control undefined variable rendering behavior through the undefinedType option when constructing a new Liquid environment.

Default undefined

The default Undefined type is silent. It renders to the empty string, is falsy when tested for truthiness, and yields an empty iterable when looped over with the {% for %} tag.

Hello {{ nosuchthing }}
{% for thing in nosuchthing %}
{{ thing }}
{% endfor %}
output
Hello



Strict undefined

The StrictUndefined type throws an UndefinedVariableError in all contexts, even when tested for truthiness with the {% if %} tag.

import { Environment, StrictUndefined } from "liquidscript";

const liquid = new Environment({ undefinedType: StrictUndefined });
const template = liquid.parse("{{ nosuchthing }}");

template.render().then(console.log);
// UndefinedVariableError: 'nosuchthing' is undefined

Note that UndefinedVariableError inherits from DetailedLiquidError, giving us the opportunity to capture or output useful diagnostic information.

import {
DetailedLiquidError,
Environment,
StrictUndefined,
} from "liquidscript";

const liquid = new Environment({ undefinedType: StrictUndefined });

const template = liquid.parse(
"{% if nosuchthing %}TRUE{% else %}FALSE{% endif %}",
);

(async () => {
try {
await template.render();
} catch (err) {
if (err instanceof DetailedLiquidError) {
console.error(err.render());
} else {
throw err;
}
}
})();
output
name error: 'nosuchthing' is undefined
-> 1:6
|
1 | {% if nosuchthing %}TRUE{% else %}FALSE{% endif %}
| ^^^^^^^^^^^ 'nosuchthing' is undefined

Falsy strict undefined

The FalsyStrictUndefined type is similar to StrictUndefined, but can be tested for truthiness and equality without throwing an exception.

import {
DetailedLiquidError,
Environment,
FalsyStrictUndefined,
} from "liquidscript";

const liquid = new Environment({ undefinedType: FalsyStrictUndefined });

const template = liquid.parse(
"{% if nosuchthing %}TRUE{% else %}FALSE{% endif %}",
);

(async () => {
try {
console.log(await template.render());
} catch (err) {
if (err instanceof DetailedLiquidError) {
console.error(err.render());
} else {
throw err;
}
}
})();
output
FALSE

Customizing undefined variable behavior

All of the built-in Undefined types are implemented as drops and are accessed exclusively through the drop API. This means you can inherit from Undefined and override any drop methods to customize undefined variable behavior.