Hone logo
Hone
Problems

Advanced Type Utilities with never in TypeScript

TypeScript's never type represents values that never occur. This challenge focuses on leveraging never to create reusable type utility functions that enhance type safety and expressiveness. You'll build utilities that manipulate types based on the absence of values, enabling more robust and predictable code.

Problem Description

Your task is to implement three TypeScript type utility functions that utilize the never type to achieve specific type transformations. These utilities will help you refine and constrain types based on the presence or absence of certain properties or conditions.

  1. PickNever<T, K>: This utility should take a type T and a set of keys K. It should return a type that picks only the properties from T where the key is in K and the property's type is never. Essentially, it filters properties based on both key inclusion and a never type.

  2. OmitNever<T, K>: This utility should take a type T and a set of keys K. It should return a type that omits only the properties from T where the key is in K and the property's type is never. This is the inverse of PickNever.

  3. FilterNever<T, Condition>: This utility should take a type T (an object type) and a conditional type Condition. The Condition should be a type predicate that evaluates to true for properties where the type is never. It should return a type that picks only the properties from T where the Condition evaluates to true.

Examples

Example 1: PickNever

type MyType = {
  a: never;
  b: string;
  c: number;
  d: never;
};

type PickedType = PickNever<MyType, 'a' | 'd' | 'e'>; // Expected: { a: never; d: never; }

Explanation: PickNever selects properties 'a' and 'd' because they exist in MyType and their types are never. 'e' is ignored because it's not a property of MyType.

Example 2: OmitNever

type MyType = {
  a: never;
  b: string;
  c: number;
  d: never;
};

type OmittedType = OmitNever<MyType, 'a' | 'd' | 'e'>; // Expected: { b: string; c: number; }

Explanation: OmitNever removes properties 'a' and 'd' because they exist in MyType and their types are never. 'e' is ignored because it's not a property of MyType.

Example 3: FilterNever

type MyType = {
  a: never;
  b: string;
  c: number;
  d: never;
  e: boolean;
};

type FilteredType = FilterNever<MyType, (key: string) => T extends { [key]: infer U } ? U extends never ? true : false : false>; // Expected: { a: never; d: never; }

Explanation: FilterNever filters based on the provided condition. The condition checks if the property type U is never. Properties 'a' and 'd' satisfy this condition, so they are included in the resulting type.

Constraints

  • All utility types must be implemented using TypeScript's type system (no runtime code).
  • The Condition type in FilterNever must be a type predicate that can be evaluated at compile time.
  • The input types T for all utilities must be object types.
  • The keys K in PickNever and OmitNever must be union types of string literal types.
  • Performance is not a primary concern; focus on correctness and type safety.

Notes

  • The never type is crucial for these utilities. Understand its meaning and how it interacts with other type operations.
  • Consider using conditional types and mapped types to achieve the desired transformations.
  • The FilterNever utility is the most complex. Break down the condition into smaller, more manageable parts. Think about how to access the type of a property within a mapped type.
  • Thoroughly test your utilities with various input types and key combinations to ensure they behave as expected.
Loading editor...
typescript