type-fest icon indicating copy to clipboard operation
type-fest copied to clipboard

Suggestion: `PropagateNever`

Open HunterKohler opened this issue 1 year ago • 3 comments

Proposal

A type PropagateNever would allow for better API typing to indicate error conditions.

Namely, in the case where there is deeply nested never in an object, the type would propagate that up to the top of said object. Thus, the branch would be removed from parent unions, or propagate to the root type itself.

Usage:

type A = PropagateNever<never> // Type: never
type C = PropagateNever<{ x: never }> // Type: never
type B = PropagateNever<[boolean, never]> // Type: never
type D = PropagateNever<string | number | { x: never }> // Type: string | number

A practical use-case:

In the type-fest type Jsonify, a deeply nested bigint value will only replace that value with never. This is the expected behavior because Jsonify is for type manipulation. However, if applied to a actual function, let's call it jsonify, propagating the never to the top would more clear to a user that the function will throw.

declare function jsonify<T>(value: T): Jsonify<T>;
declare function jsonifyStrict<T>(value: T): PropagateNever<Jsonify<T>>;

declare const input: { field: bigint };

const result1 = jsonify(input) // Type: { field: never }
const result2 = jsonifyStrict(input) // Type: never

Furthermore, typescript does not do analyze branches for deeply nested nevers, only top level ones. For example, with typescript compiler option noImplicitReturns set to true, jsonify gives an error in the following case, but jsonifyStrict does not:

function f(x: boolean) {
    if (x) {
        return x;
    }
    
    jsonify({ x: 0n });
}

Implementation

I have not yet implemented this type, but expect it to be possible, and will update this comment when time allows me to do so.

HunterKohler avatar Jul 17 '22 16:07 HunterKohler

Looks like a useful type to me. Can you think of any other use-cases for it?

sindresorhus avatar Jul 19 '22 13:07 sindresorhus

I really like this idea, I see quite a few cases in internal type management, especially in those that are recursive. If you want I can try to do it!?

skarab42 avatar Aug 26 '22 08:08 skarab42

@skarab42 Go for it 👍

sindresorhus avatar Aug 26 '22 21:08 sindresorhus