Ta bort fält av typen `never` rekursivt från en typ i TypeScript


I TypeScript, om en objekttyp innehåller ett fält vars typ är never, kan du egentligen inte instansiera ett objekt av den typen. Exempel:

type x = { a: string; b: never };
const xx: x = { a: "asd" }; // property 'b' is missing

Jag tänkte att det kanske skulle vara användbart (faktiskt tänkte jag mest att det skulle vara en rolig utmaning) att kunna ta bort alla fält som inte kan tilldelas, och min lösning är:

/** Recursively decays all fields that are of type `never` from `T`.
 * @example DecayNever<number> // yields number
 * @example DecayNever<{ x: number; y: string; z: never }> // yields { x: number; y: string }
 * @example DecayNever<{ x: number; y: { z: never } }> // yields { x: number }
 * @example DecayNever<{ x: number; y: { z: never, w: string } }> // yields { x: number, y: { w: string } }
 * @example DecayNever<{ a: { b: { c: never } } }> // yields never
 */
export type DecayNever<T> = T extends Record<string | number | symbol, unknown>
    ? FilteredKeys<{ [K in keyof T]: DecayNever<T[K]> }> extends never
        ? never
        : Pick<DecayNeverType<T>, FilteredKeys<DecayNeverType<T>>>
    : T;

type DecayNeverType<T> = { [K in keyof T]: DecayNever<T[K]> };

/** Returns a union of all keys of `T` where `T[K]` is not `never` */
type FilteredKeys<T> = { [K in keyof T]: T[K] extends never ? never : K }[keyof T];

type t_1 = DecayNever<number>;
type t_2 = DecayNever<{ x: number; y: string; z: never }>;
type t_3 = DecayNever<{ x: number; y: { z: never } }>;
type t_4 = DecayNever<{ x: number; y: { z: never, w: string } }>;
type t_5 = DecayNever<{ a: { b: { c: never } } }>;

lekplatslänk

Det verkar faktiskt fungera, även om det är väldigt, tja, skakigt. Jag är förvånad över att det inte finns en inbyggd metod för att göra detta, men finns det ett bättre sätt att göra det på? Det känns väldigt oelegant, och kontrollen för att säkerställa att FilteredKeys<...> inte är never är för att Pick<T, never> resulterar i typen {} (vilket jag tror är något liknande any?).

Relaterade artiklar