Utilizing brand enums for nominal typing in TypeScript 3 has been a challenge for me. The code snippet below demonstrates the issue:
export enum WidgetIdBrand {}
export type WidgetId = WidgetIdBrand & string;
const id:WidgetId = '123' as WidgetId;
Although this code works perfectly in TypeScript 2.8 and 3.0.3, I encountered a problem when unioning WidgetId with other types in TS 3.0.3. The compiler seems to be treating (EnumType & string) as 'never' only when it's in a union:
const id2: WidgetId | null = id;
// Type 'WidgetId' is not assignable to type 'null'.
Interestingly, some union combinations work fine while others don't:
const id1: WidgetId = id; // works
const id2: WidgetId | null = id; // error
const id3: WidgetId | undefined = id; // error
const id4: WidgetId | number = id; // works!?
const id5: WidgetId | boolean = id; // error
const id6: WidgetId | { kind: 'bar' } = id; // error
const id7: WidgetId | {} = id; // works!?
Is there a workaround to make brand enums function correctly in unions in TypeScript 3?