TypeDrop

2026-06-23 Challenge

2026-06-23 Medium

Typed Feature Flag Evaluator with Targeting Rules & Rollout

You're building the feature-flag evaluation engine for a SaaS platform. Raw flag configurations arrive as `unknown` from a remote config service; your evaluator must validate them, match each flag's targeting rules against a typed user context, apply percentage-based rollouts, and return a strongly-typed evaluation report — with zero `any`.

Goals

  • Implement `parseFlag` to validate `unknown` flag configs into `FeatureFlag` using only type-narrowing guards (no `as`).
  • Implement `evaluateFlag` to apply targeting rules in order using all five `RuleOperator` semantics, respecting the disabled and rollout-bucket checks.
  • Implement `evaluateFlags` to orchestrate parsing and evaluation, skip invalid flags into an errors array, and produce a fully-typed `EvaluationReport`.
  • Ensure `rolloutPercentage` correctly gates non-default variants using `deterministicHash(flagKey:userId) % 100`.
challenge.ts
export type RuleOperator = "eq" | "neq" | "in" | "gt" | "lt";

export interface FeatureFlag {
  key: string;
  description: string;
  enabled: boolean;
  rules: TargetingRule[];
  defaultVariant: string;
  rolloutPercentage: number; // 0–100
}

export interface UserContext {
  userId: string;
  email: string;
  country: string;
  plan: "free" | "pro" | "enterprise";
  accountAgeDays: number;
}

export type Result<T, E> =
  | { ok: true; value: T }
  | { ok: false; error: E };

// Validate raw unknown → FeatureFlag
export function parseFlag(raw: unknown, index: number): Result<FeatureFlag, ValidationError>;

// Evaluate one flag for a user → variant + reason
export function evaluateFlag(flag: FeatureFlag, user: UserContext): FlagEvaluation;

// Parse all raws, evaluate each, return a typed report
export function evaluateFlags(
  rawFlags: unknown[], user: UserContext, errors: ValidationError[]
): EvaluationReport;
Hints (click to reveal)

Hints

  • For `parseFlag`, build up a validated object field-by-field using `typeof` and `Array.isArray` checks — `keyof UserContext` can be validated against a hard-coded set like `new Set(["userId", "email", ...])`.
  • In `evaluateFlag`, handle the four evaluation steps in strict order (disabled → rollout → rules → default) before touching any rule logic.
  • For the `"in"` operator, remember `ruleValue` must be `string[]` — narrow it with `Array.isArray` before calling `.includes`.

Or clone locally

git clone -b challenge/2026-06-23 https://github.com/niltonheck/typedrop.git