Whetstone.
The Fusion domain kitSmartEnums, not string literals
Module 8 · Lesson 313 min

SmartEnums, not string literals

When a value belongs to a known, finite set (a disruption cause, a decision type), the TS habit is a string union: type Reason = 'weather' | 'mechanical'. In Fusion that’s slop (anti-pattern #2). The set lives in the backend as a SmartEnum: an enum-shaped object that carries a stable slug, a display label, and any per-member data, with lookup and equality built in.

A SmartEnum (real DisruptionReason, trimmed)
public class DisruptionReason : SmartEnum<DisruptionReason, string>
{
    public static readonly DisruptionReason Mechanical = new(
        nameof(Mechanical), "mechanical", "Mechanical / Technical", isExtraordinary: false, displayOrder: 0);
    public static readonly DisruptionReason Weather = new(
        nameof(Weather), "weather", "Weather", isExtraordinary: true, displayOrder: 6);

    private DisruptionReason(string name, string value, string displayLabel, bool isExtraordinary, int displayOrder)
        : base(name, value)
    {
        DisplayLabel = displayLabel;
        IsExtraordinary = isExtraordinary;
        DisplayOrder = displayOrder;
    }

    public string DisplayLabel { get; }
    public bool IsExtraordinary { get; }
}

The two-part identity matters. Name is the PascalCase C# identifier (nameof(Mechanical)). Value is the kebab-case slug ("mechanical") that gets persisted and sent over the wire, so it’s a public contract you don’t change casually. You get .List, .FromValue, .TryFromValue, .FromName, and value-based equality without writing any of them.

Practice

Try it yourself

Do

Read a SmartEnum end to end

See the whole pattern: members, extra data, Parse, and the endpoint projection.

  • Open domain/Enums/DisruptionReason.cs and read the static members and their nameof/slug/label triples
  • Find Parse(string code) and note it returns Result<DisruptionReason>, wrapping TryFromValue
  • Open a *Endpoints.cs that serves an enum list and note it projects to a small DTO (Code, DisplayLabel), never the raw member
  • Confirm no TypeScript union anywhere mirrors these values
Done whenYou can name where the set is defined (SmartEnum), how it's parsed safely (Parse returning Result), and how it reaches the FE (DTO projection, one source of truth).
Recall

Name versus Value

This distinction is a contract, so hold it exactly.

In a Fusion SmartEnum, what is the difference between the Name and the Value, and which one must you not change casually?

Reveal answer

Name is the PascalCase C# identifier (e.g. Mechanical, via nameof). Value is the kebab-case slug (e.g. "mechanical") that is persisted to the database and sent over the API. Value is a public contract, so changing it breaks stored data and clients; add a new member and deprecate instead of editing a Value.

Sign in to track your progress →