0.1.0 • Published 27 days ago

unnarrowed v0.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
27 days ago

narrowable

A type-only TypeScript library for detecting unnarrowed types and asserting narrowing of generic types.

What can I do with this?

Types

Unnarrowed

A type that has not been narrowed yet.

type Unnarrowed<T>

Usage:

interface AssociatedTypes {
    DateType: Unnarrowed<Date | number | string>
}

NarrowedFrom

The narrowed form of an Unnarrowed type.

If used on the right-hand side of an extends statement such as MyClass<U extends NarrowedFrom<T>> where T is Unnarrowed, it will cause an error when U = T.

type NarrowedFrom<T>

Behavior:

  • If T is Unnarrowed<U>, returns U.
  • If T is an object with Unnarrowed<U> properties, the Unnarrowed is stripped from them.
  • Otherwise, returns an error type.

Usage:

type DateType = Unnarrowed<Date | number | string>
type DateGetter<T extends NarrowedFrom<DateType> = NarrowedFrom<DateType>> = () => T;
//                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <-- assert narrowing

/** Defined elsewhere */
declare function getPublishDate(package: string): DateType;

/**
 * Prints a date returned by a DateGetter.
 */
function printDateFrom<F extends DateGetter>(getter: F) {
    console.log(getter());
}

printDateFrom(() => new Date()); // ok
printDateFrom(() => getPublishDate("unnarrowed"));
//                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <-- error, it returns unnarrowed DateType

AssertNarrowed

Asserts that the given type has been narrowed from an Unnarrowed<U>.

type AssertNarrowed<T, Options = {}>

Options:

{

    // If set to `true`, the assertion will only pass if the type is
    // narrowed to a single, non-union type.
    strict?: true | false
    
    // If set, this type will be returned when the assertion fails.
    failType: any;

}

Usage:

type GlasswareMaterial = Unnarrowed<'glass' | 'crystal'>;
interface Glassware<T extends GlasswareMaterial> {
    type: AssertNarrowed<T, {
        strict: true,
        failType: never,
    }>
}
const aWineGlass: Glassware<'glass' | 'crystal'> = {
    type: "glass"
//  ~~~~ <-- T is not strictly narrowed, so `type` is never
}

AssertStrictlyNarrowed

An alias for AssertNarrowed with the strict option set to true.

type AssertStrictlyNarrowed<T, Options = {}>

Utility Types

IsUnnarrowed

Checks if a type is Unarrowed<T>.

If the given type is any, an error type will be returned.

type IsUnnarrowed<T, WhenTrue=true, WhenFalse=false, WhenError=/* error */>

Usage:

type should_be_true  = IsUnnarrowed<Unnarrowed<string>>;
type should_be_false = IsUnnarrowed<string>;
type is_error        = IsUnnarrowed<any>;

IsNarrowed

Checks if a type is not Unarrowed<T>.

If the given type is any, the WhenTrue type will be returned.

type IsUnnarrowed<T, WhenTrue=true, WhenFalse=false, WhenError=WhenTrue>

Usage:

type should_be_true  = IsNarrowed<string>;
type should_be_false = IsNarrowed<Unnarrowed<string>>;
type also_true       = IsNarrowed<any>;

IsStrictlyNarrowed

Checks if a type is not Unarrowed<T>, and is not a type union.

If the given type is any, the WhenFalse type will be returned.

type IsUnnarrowed<T, WhenTrue=true, WhenFalse=false, WhenError=WhenTrue>

Usage:

type should_be_true  = IsStrictlyNarrowed<string>;
type should_be_false = IsStrictlyNarrowed<Unnarrowed<string>>;
type also_false_1    = IsStrictlyNarrowed<string | boolean>;
type also_false_2    = IsStrictlyNarrowed<any>;