SimplyTyped

repository·master·Indexed 20 days ago

https://github.com/andnp/simplytyped

A TypeScript utility library providing advanced type manipulation tools for objects, strings, tuples, numbers, and conditionals. Version 1.1.0 includes helpers such as DeepPartial, DeepReadonly, StrictUnion, and UnionToIntersection, as well as type-level math operations and runtime utilities like isKeyOf and objectKeys.

Tokens
9.1K
Snippets
66
Records
74
Agent score
67%

What's inside simplytyped

  1. Overview of SimplyTyped

    master
    SimplyTyped is a TypeScript utility library designed to provide the building blocks for creating concise and complex types. Unlike more experimental libraries, it aims to be driven by industry use cases, often providing a thin layer over built-in TypeScript functionality to facilitate advanced type manipulation.
  2. Use runtime utilities: isKeyOf, objectKeys, and taggedObject

    master

    Runtime functions for object manipulation and type guarding:

    • isKeyOf(obj, key): A type guard that marks key as a valid key of obj if it exists.
    • objectKeys(obj): Returns an array of keys for the given object, with the return type correctly typed as an array of the object's keys (unlike native Object.keys).
    • taggedObject(obj, key): Transforms an object by adding a tag (the value of key) to every sub-object within it. Useful for tagged unions/reducers.
    const o = { a: 'hi', b: 22 };
    const key: string = 'a';
    
    if (isKeyOf(o, key)) {
        // key is now typed as 'a' | 'b'
    }
    
    const tagged = taggedObject({ a: { val: 1 } }, 'name');
    // Result: { a: { name: 'a', val: 1 } }
  3. Define function types with AnyFunc and Predicate

    master

    Utilities for concise function type definitions:

    • AnyFunc: Represents a function that takes any arguments and returns any. Can be specialized with a return type: AnyFunc<number> returns number.
    • ArgsAsTuple<F>: Extracts the arguments of a function F as a tuple (up to 7 arguments).
    • ConstructorFunction<T>: Represents the constructor for a type T.
    • OverwriteReturn<F, R>: Takes a function F and modifies its return type to R.
    • Predicate<T>: Defines a function that takes an argument of type T and returns a boolean.
    type F = (x: number, y: string) => any;
    type Args = ArgsAsTuple<F>; // [number, string]
    
    type P = Predicate<string>; // (arg: string) => boolean
  4. Use PromiseOr to handle sync and async types

    master

    The PromiseOr<T> utility returns the type T or a Promise containing T. This is helpful when a function might return a value immediately or wrap it in a promise.

    type got = PromiseOr<string>; // Promise<string> | string
  5. Perform math operations on numeric types

    master

    SimplyTyped allows performing basic arithmetic at the type level:

    • Add<A, B>: Adds two numbers.
    • Sub<A, B>: Subtracts B from A.
    • Next<T>: Returns T + 1.
    • Prev<T>: Returns T - 1.
    • IsOne<T>, IsZero<T>: Boolean checks for 1 and 0.
    • NumberEqual<A, B>: Returns True if numbers are equivalent.
    • NumberToString<T>: Converts a number type to its string literal equivalent.
    type sum = Add<12, 38>; // 50
    type diff = Sub<22, 12>; // 10
    type str = NumberToString<22>; // '22'
  6. Use NoDistribute to prevent conditional type distribution

    master

    In TypeScript, conditional types distribute over unions when the checked type is a naked type parameter. NoDistribute<T> prevents this behavior by wrapping the type in a way that makes it no longer 'naked', ensuring the conditional is evaluated once against the entire union rather than once for each member.

    Note: NoDistribute must be used within the definition of the conditional type itself to be effective. Passing a NoDistribute-wrapped type into a standard distributive conditional will still result in distribution.

    type IsString<T> = T extends string ? "Yes" : "No";
    type IsStringNoDistribute<T> = NoDistribute<T> extends string ? "Yes" : "No";
    
    // Evaluates as: ("foo" | 42) extends string ? "Yes" : "No"
    type T2 = IsStringNoDistribute<"foo" | 5>; // Result: "No"
  7. Manage nullability with Nullable and NonNullable

    master

    SimplyTyped provides utilities to explicitly manage null and undefined in types:

    • Nullable<T>: Marks a type as T | null | undefined.
    • NonNullable<T>: Removes null and undefined from a type (Note: this may overlap with the built-in TypeScript NonNullable).
    type got = Nullable<string>; // string | null | undefined
    
    type notNull = NonNullable<Nullable<string>>; // string
  8. Use conditional logic with And, Or, Not, If, etc.

    master

    Implement complex conditional logic using boolean type utilities:

    • If<Condition, TrueType, FalseType>: Returns TrueType if Condition is True, otherwise FalseType.
    • And<A, B>, Or<A, B>, Xor<A, B>, Nand<A, B>, Not<A>: Standard boolean logic gates.
    type conditional<C extends Bool> = If<C, number, string>;
    
    type res = conditional<True>; // number
  9. Convert unions to intersections with UnionToIntersection

    master

    The UnionToIntersection<T> utility converts a union type into an intersection type. This is particularly useful for transforming a union of objects into a single object containing all properties from the union members.

    type got = UnionToIntersection<{ a: 0 } | { b: 1 } | { c: 2 }>;
    // Result: { a: 0, b: 1, c: 2 }
  10. Use NoInfer to prevent type inference in generic functions

    master

    The NoInfer<T> utility prevents a specific type parameter from being used to infer the type T in a generic function. This is useful when you have multiple arguments and want to ensure that the type of one argument does not influence the inferred type of the generic parameter, even if they are related in a union.

    function doStuff<T>(x: T, y: NoInfer<T | 'there'>): T { return x; }
    
    const hi = 'hi' as 'hi' | number;
    const there = 'there';
    const x = doStuff(hi, there);
    // x is inferred as 'hi' | number, not influenced by 'there'