Flavored types (optional symbol property intersection) lose discrimination when base type is a complex template literal
01:25 21 Apr 2026

I'm using the flavored types pattern (optional discriminant property via symbol intersection) and noticed it silently stops working when the base type is a template literal with a union in one of its placeholders.

const FLAVOR = Symbol("flavor");

// ✅ Works: number base
type VendorId = number & { [FLAVOR]?: "vendor" };
type MachineId = number & { [FLAVOR]?: "machine" };
declare const vendorId: VendorId;
declare function acceptMachineId(id: MachineId): void;
acceptMachineId(vendorId); // Error ✅

// ✅ Works: simple template literal base
type SimplePhone = `+${number}`;
type SimpleA = SimplePhone & { [FLAVOR]?: "a" };
type SimpleB = SimplePhone & { [FLAVOR]?: "b" };
declare const simpleB: SimpleB;
declare function acceptSimpleA(a: SimpleA): void;
acceptSimpleA(simpleB); // Error ✅

// ❌ Breaks: complex template literal with union in placeholder
type CountryCode = 1 | 33 | 44;
type PhoneNumber = `+${CountryCode}${number}${number}`;
type Whistleblower = PhoneNumber & { [FLAVOR]?: "whistleblower" };
type Relay = PhoneNumber & { [FLAVOR]?: "relay" };
declare const relay: Relay;
declare function acceptWhistleblower(w: Whistleblower): void;
acceptWhistleblower(relay); // No error ❌ — should be rejected

// ✅ Workaround: required (branded) property instead of optional
const BRAND = Symbol("brand");
type BrandedWhistleblower = PhoneNumber & { [BRAND]: "whistleblower" };
type BrandedRelay = PhoneNumber & { [BRAND]: "relay" };
declare const brandedRelay: BrandedRelay;
declare function acceptBrandedWhistleblower(w: BrandedWhistleblower): void;
acceptBrandedWhistleblower(brandedRelay); // Error ✅

My question: Why does adding a union type in a template literal placeholder (e.g. +${CountryCode}... where CountryCode = 1 | 33 | 44) make two differently-flavored types mutually assignable? And is there any workaround other than switching to a required (branded) property?

typescript typescript-template-literals