TGViewer
Настоящий JavaScript Настоящий JavaScript @true_js · 5.89K subscribers
Post #3605 333
⁣Feature flags на TypeScript: типобезопасная композиция с branded types и runtime validation для production-конфигураций

Feature flags в production — удобно, но конфиги часто превращаются в мешанину строк. Простое { isNewFeature: true } не защищает от опечаток вроде isNewFeautre, и линтер молчит до прогона тестов или деплоя. Используем branded types с Zod для строгой проверки на этапе компиляции и выполнения.

Branded types для compile-time безопасности
Тип Brand<T, B> добавляет уникальную метку. Передать простой boolean вместо NewFeature не выйдет — TS потребует явного приведения. Это исключает путаницу между флагами:

type Brand<T, B> = T & { __brand: B };
type NewFeature = Brand<boolean, 'NewFeature'>;
type LegacyFallback = Brand<boolean, 'LegacyFallback'>;

function useFeature(newFeature: NewFeature, legacyFallback: LegacyFallback): boolean {
return newFeature || legacyFallback;
}


Runtime validation с Zod
Даже с branded types в JSON может прилететь невалидное значение. Добавляем схему с z.boolean().brand() — тогда при парсинге ошибка будет явной, а не тихим undefined:

const ConfigSchema = z.object({
newFeature: z.boolean().brand<'NewFeature'>(),
legacyFallback: z.boolean().brand<'LegacyFallback'>(),
});
type Config = z.infer<typeof ConfigSchema>;

function loadConfig(raw: unknown): Config {
return ConfigSchema.parse(raw);
}


Дискриминируемые union для состояний флагов
Когда два флага конфликтуют (например, newFeature и legacyFallback), обычные типы не мешают включить оба одновременно. Discriminated union сужает область до корректных комбинаций — это предотвращает два источника истины:

type FlagState = 
| { newFeature: true; legacyFallback: false }
| { newFeature: false; legacyFallback: boolean };

function processState(state: FlagState) {
if (state.newFeature) {
return state.legacyFallback; // TS сужает до false
}
return state.legacyFallback;
}


* Предупреждение: branded types добавляют шум в код и усложняют вложенные конфиги без линтера. Для плоских A/B тестов и канареечных релизов это окупается — ошибка ловится на этапе компиляции, а не в production.
* Совет: комбинируй discriminated union с zod-схемой на весь конфиг — тогда даже опечатка в JSON упадёт с понятным сообщением, а не молча сломает логику.

Вывод: Типобезопасная композиция флагов через branded types и runtime-валидация даёт двухуровневую защиту — compile-time строгость и runtime-проверку входных данных, что критично для надёжности A/B экспериментов и канареечных деплоев.
More from @true_js
  1. Oct 3, 2026Post #3963
  2. Oct 2, 2026😅 Айтишник отправил в одну компанию три одинаковых резюме и только одно дошло до финала О…
  3. Oct 2, 2026Post #3961
  4. Oct 2, 2026🤣 Правильно расставленные приоритеты в моей жизни би лайк: 💥 xCode Journal
  5. Oct 1, 2026🤯 Люди взбунтовались против «пыточной для ИИ» На GitHub заметили открытый проект AI Tortu…
  6. Oct 1, 2026День в Заонежье начинается ещё в дороге. Мы встретим вас в аэропорту или на вокзале. Дальш…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →