A mapped type can turn every property of one shape into a boolean flag.

mapped type `[K in keyof T]` visits each key of a type and creates a matching property in a new type.

Mapped Feature Flags

emailEnabled
feature_flags.ts
Replay: real traced execution (multi-file project)
type Profile = {
    name: string;
    email: string;
    theme: string;
};

type FeatureFlags<T> = {
    [K in keyof T]: boolean;
};

function countEnabled(flags: FeatureFlags<Profile>): string {
    const enabled: string[] = Object.keys(flags).filter((key) => flags[key as keyof Profile]);
    return `${enabled.length}:${enabled.join(",")}`;
}

const emailEnabled: boolean = true;
const flags: FeatureFlags<Profile> = {
    name: true,
    email: emailEnabled,
    theme: false,
};

console.log(countEnabled(flags));
type Profile = {
    name: string;
    email: string;
    theme: string;
};

type FeatureFlags<T> = {
    [K in keyof T]: boolean;
};

function countEnabled(flags: FeatureFlags<Profile>): string {
    const enabled: string[] = Object.keys(flags).filter((key) => flags[key as keyof Profile]);
    return `${enabled.length}:${enabled.join(",")}`;
}

const emailEnabled: boolean = false;
const flags: FeatureFlags<Profile> = {
    name: true,
    email: emailEnabled,
    theme: false,
};

console.log(countEnabled(flags));
  1. emailEnabled ← true, flags ← [object Object]

    13    return `${enabled.length}:${enabled.join(",")}`;14}1516const emailEnabled→ true: boolean = true;  //@emailEnabled=false17const flags→ [object Object]: FeatureFlags<Profile> = {18    name: true,19    email: emailEnabledtrue,20    theme: false,21};2223console.log(countEnabled(flags[object Object]));
  2. enabled ← name,email

    8    [K in keyof T]: boolean;9};1011function countEnabled(flags[object Object]: FeatureFlags<Profile>): string {12    const enabled→ name,email: string[] = Object.keys(flags[object Object]).filter((key) => flags[key as keyof Profile]);13    return `${enabled.length2}:${enabledname,email.join(",")}`;14}
  3. console.log(countEnabled(flags));

    20    theme: false,21};2223console.log(countEnabled(flags[object Object]));
    output2:name,email
  1. emailEnabled ← false, flags ← [object Object]

    13    return `${enabled.length}:${enabled.join(",")}`;14}1516const emailEnabled→ false: boolean = false;17const flags→ [object Object]: FeatureFlags<Profile> = {18    name: true,19    email: emailEnabledfalse,20    theme: false,21};2223console.log(countEnabled(flags[object Object]));
  2. enabled ← name

    8    [K in keyof T]: boolean;9};1011function countEnabled(flags[object Object]: FeatureFlags<Profile>): string {12    const enabled→ name: string[] = Object.keys(flags[object Object]).filter((key) => flags[key as keyof Profile]);13    return `${enabled.length1}:${enabledname.join(",")}`;14}
  3. console.log(countEnabled(flags));

    20    theme: false,21};2223console.log(countEnabled(flags[object Object]));
    output1:name