Open-source project
jmurphyau/ember-truth-helpers avatar
jmurphyau/ember-truth-helpers

ember-truth-helpers: composable boolean logic in Ember templates

Ember HTMLBars Helpers for {{if}} & {{unless}}: not, and, or, eq & is-array

701 stars94 forksTypeScriptMIT

At a glance

What is it?
ember-truth-helpers is a v2 Ember addon that adds a family of boolean helpers, so a template can say (and a b) or (not a) instead of relying on the built-in truthiness rules. It is a small TypeScript package with Glint types, a narrow compatibility floor, and a helper table that documents its own argument rules.
Who is it for?
Adopt ember-truth-helpers if you write Ember templates where the default truthiness rules read badly, particularly for negated conditions, multi-clause and conditions, and comparisons against null or undefined. Do not adopt it if your templates are simple enough that the built-in conditionals already say what you mean, and do not adopt it on an Ember version below 4.8 or without Embroider or ember-auto-import 2 or newer, since the package is a v2 addon.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 31 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the addon adds to the template language

ember-truth-helpers provides HTMLBars template helpers for additional truth logic in if and unless statements. The repository description puts it more bluntly: helpers for if and unless, covering not, and, or, eq and is-array among others.

The problem it addresses is specific to template languages. In JavaScript you can write a condition of any complexity, but inside an Ember template the conditional is an expression that has to be readable at a glance in the markup. A double negative such as a negated check reads badly, and a two clause condition has to be expressed with the built-in truthiness semantics rather than with the operator the developer actually means.

The addon solves that by giving each logical operation a name and a helper form. A condition becomes something like {{if (and a b)}} or {{if (not a)}} rather than a nested expression, and the same helpers work in unless statements because they are expressions in a condition position.

The compatibility floor is stated plainly: Ember.js v4.8 or above, and Embroider or ember-auto-import 2 or newer, because the package follows the v2 addon package format. That constraint is a genuine filter for older applications, and it is the kind of detail that decides whether an addon can be adopted at all.

The helper table and the argument rules it encodes

The README documents the helpers in a table with four useful columns: the JavaScript operation each one mirrors, the HTMLBars form, the import name, and whether a variable argument count is allowed.

The table covers eq, not-eq, not, and, or, xor, gt, gte, lt, lte, is-array, is-empty and is-equal. The JavaScript column is the mental model: eq stands for strict equality, and stands for a logical conjunction, or for a disjunction, not for a negation, is-array for a check on whether the value is an array, is-empty for an emptiness check, and is-equal for a deep comparison against a primitive.

The last column is the one that catches people. The helpers that take a variable argument count are not, and, or and is-array. The comparison helpers, which take exactly two values, are not. That is a sensible division: and and or are naturally variadic while a comparison is not, and it means you cannot accidentally pass a third argument to eq and have it silently ignored.

The import column matters too, because the helpers are also usable outside templates. Each one is importable by name from the package, so a component class or a test can evaluate the same predicate the template uses, and the naming convention is that the dashed template name maps to a camel case JavaScript identifier.

One detail in that table is worth flagging rather than repeating: the row for lte lists the import as eq, which looks like a copy and paste slip in the documentation rather than an intended API. If you plan to use the less-than-or-equal helper in JavaScript, verify the exported name yourself.

eq versus is-equal for objects

The API section picks out one pair of helpers and explains the difference, and the explanation is short enough to be worth repeating in your own head.

is-equal uses the Ember.isEqual helper to evaluate equality of two values. The documentation then gives the guidance: eq should be sufficient for most applications, and is-equal is necessary when trying to compare a complex object to a primitive value.

That distinction is about how equality is computed. The strict equality that eq mirrors is a reference and value comparison, so two different objects with the same shape are not equal. The deep comparison that is-equal performs will say they are, which is what you want when you are comparing, say, a plain configuration object against a value you constructed. It is also what you do not want when you are checking identity, because deep comparison is more expensive and can report equality where identity is what mattered.

The practical guidance for a template is that a structural check needs is-equal and an identity check needs eq, and the rule of thumb in the documentation is to reach for eq first.

Installing the addon and pulling it into a template

Installation is the standard Ember CLI command:

bash
ember install ember-truth-helpers

The package is published as an npm package under the name ember-truth-helpers, with a package.json that declares a single runtime dependency, @embroider/addon-shim, which is the shim that makes a v2 addon work with the classic build. The build itself is a rollup configuration, and the package exports types and compiled JavaScript side by side through the exports field, with the type definitions resolved from a declarations directory.

The template usage is the form the table shows. Because the helpers are ordinary helpers, you use them inside the conditional expression:

gts
import { or } from 'ember-truth-helpers';

<template>
  {{#if (or @admin @user)}}
    Admin Controls are going here
  {{/if}}
</template>

The single file component example is instructive for a specific reason. It imports or from the package index and uses it with the @argument syntax, which is the strict template argument a component receives. Nothing about the helper changes in gts or gjs files, all helpers are exported from the index, and the same helper works in a classic template with positional parameters and in a single file component with named arguments.

The last row of the same pattern appears in the template as {{#if}} with a subexpression around the helper call. The helper is evaluated to a boolean first, and the block conditional then branches on that boolean, which is what keeps the logic out of the raw truthiness rules that the built-in conditional applies to a plain value.

Glint types and the moduleResolution requirement

The addon is Glint enabled, and the README gives the exact registration snippet to add to a types/global.d.ts file:

ts
import '@glint/environment-ember-loose';

import type EmberTruthRegistry from 'ember-truth-helpers/template-registry';

declare module '@glint/environment-ember-loose/registry' {
  export default interface Registry extends EmberTruthRegistry, /* other addon registries */ {
    // local entries
  }
}

The pattern is the standard one for a Glint enabled addon. The addon publishes a template registry type, the application imports that registry type, and the application's registry interface extends it alongside the registries of any other addons in the project. Once that is in place, the helpers get type checking in templates in the same way as the built-in ones.

There is a catch that the README calls out, and it is a common one for any modern package with an exports field. Types are made available through the package.json exports field, and for TypeScript to recognise that, beginning from TS 4.7, moduleResolution has to be set to node16 or nodenext. An application on the older node or bundler resolution will not find the declarations even though they are shipped in the package, and the symptom is a type error saying the module has no exported member rather than anything that points at moduleResolution.

The repository layout backs up the tooling story. The lint script fans out to several sub commands, one per linter: a template lint with ember-template-lint, a JavaScript lint with eslint, and two Glint runs, one for the project and one for the type-tests directory, which exists so that the type level behaviour of the helpers is itself tested. There is a separate type-tests folder, a publish-specific tsconfig, and a rollup config for the build.

Where a helper addon stops being the answer

The first limitation is the compatibility floor again, and it is decisive. Ember.js v4.8 or above plus Embroider or ember-auto-import 2 or newer is a requirement, and a project on an older Ember or on the classic build has no way to take this addon without a migration that is far larger than adding a helper library.

The second limitation is that the helpers only work in condition positions. They are expressions that produce a boolean, which means they can be used in if and unless, but they are not a general expression language. Once a template condition needs arithmetic, a comparison chain, or a computed value, the helper set does not stretch, and the developer ends up writing a getter or a computed property in the component class, which is the answer the framework was already offering.

The third limitation is the ecosystem one. The README points to two related addons, ember-get-helper for pulling values out of objects in templates and ember-composable-helpers from DockYard for composing helpers in general. The existence of those projects says something useful: the helper ecosystem in Ember is a set of small focused addons, and the boundaries between them are real. A template that needs a value lookup and a boolean check ends up depending on two packages, each with its own compatibility floor.

The real alternative is the framework's own path. A computed property or a getter on the component class gives you the same expressiveness, is type checked, and needs no dependency. The trade is where the logic lives. Helpers keep the decision in the template, next to the markup, which is what some teams want for readability, while a getter moves it to the class where it can be unit tested in isolation. The decision is stylistic and architectural rather than technical, and the addon exists because a lot of Ember developers have made the same choice.

Editorial conclusion

Adopt ember-truth-helpers if you write Ember templates where the default truthiness rules read badly, particularly for negated conditions, multi-clause and conditions, and comparisons against null or undefined. Do not adopt it if your templates are simple enough that the built-in conditionals already say what you mean, and do not adopt it on an Ember version below 4.8 or without Embroider or ember-auto-import 2 or newer, since the package is a v2 addon. Before you upgrade, read the helper table's variable argument column, because not every helper accepts extra arguments, and check that your TypeScript moduleResolution is set to node16 or nodenext so the published types are picked up.

Frequently asked questions

What is ember-truth-helpers?

It is an Ember addon providing HTMLBars template helpers for additional truth logic in if and unless statements, including not, and, or, eq, not-eq, xor, gt, gte, lt, lte, is-array, is-empty and is-equal. It is MIT licensed and written in TypeScript.

How do I install ember-truth-helpers?

Run ember install ember-truth-helpers from your Ember project. The package requires Ember.js v4.8 or above and Embroider or ember-auto-import 2 or newer, since it follows the v2 addon package format.

When should I use is-equal instead of eq in ember-truth-helpers?

The documentation says eq should be sufficient for most applications, and is-equal is necessary when trying to compare a complex object to a primitive value. is-equal uses the Ember.isEqual helper, while eq mirrors a strict equality check.

Do the ember-truth-helpers support Glint and single file components?

Yes. The addon is Glint enabled, and the README gives the types/global.d.ts registration snippet that extends the addon template registry. All helpers are exported from the index, so they can be imported and used in gts or gjs single file components, and TypeScript needs moduleResolution set to node16 or nodenext to find the shipped types.

Which ember-truth-helpers accept a variable number of arguments?

According to the helper table, not, and, or and is-array allow a variable argument count, while eq, not-eq, xor, gt, gte, lt, lte, is-empty and is-equal do not and take exactly the values they compare.

Official sources

  1. Issues
  2. jmurphyau/ember-truth-helpers on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jmurphyau-ember-truth-helpers.svg)](https://hysenlabs.com/projects/jmurphyau-ember-truth-helpers)

Was this useful?