npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

cast-as-trophy

v0.0.8

Published

Build the type guards you want for the supported types you can

Downloads

10

Readme

Cast as Trophy Cast as Trophy

Gitlab pipeline status Gitlab code coverage Libraries.io dependency status for latest release NPM npm type definitions npm

Build the type guards you want for the supported types you can! And enjoy your compile time errors when you forget to keeping something up to date! ;)

The rules of the supported types:

| No. | Rule | Example | | --- | -------------------------------------------------------------------------------- | -------------------------------------------- | | 1. | Objects with string, number or boolean properties | { s: string } | | 2. | Supported objects can be embedded | { i: { s: string } } | | 3. | Arrays can be used for the supported types and objects | { ia: Array<{ s: string }> } | | 4. | The supported types and objects can be optional with null and / or undefined | { iau: Array<{ s: string }> \| undefined } |

The library is not optimized for performance. And it is built for TypeScript (with strictNullChecks option turned on).

How to start?

You can install the library with NPM:

npm i --save cast-as-trophy

And create a caster for a not too complex object type:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string; // You need to call `addString("s")`
    n: number; // You need to call `addNumber("n")`
    b: boolean; // You need to call `addBoolean("b")`
}

const exampleCaster = createCaster<Example>()
    .addString("s") // Needed because of `s: string`
    .addNumber("n") // Needed because of `n: number`
    .addBoolean("b") // Needed because of `b: boolean`
    .build();

And check some values:

const test: unknown = {
    s: "test",
    n: 42,
    b: true,
};

if (exampleCaster.isType(test)) {
    // The `test` is type guarded! It has the proper type here.
    console.log(`Value of s: ${test.s}`);
}

How to use a caster?

1. isType<TYPE>(value: unknown) => value is TYPE

A simple old fashion type guard.

| | | | ------------- | ----------------------------------------------------------------------- | | Input | Value to check | | Result | Whether the value has the proper type (boolean, but the type guard way) | | Exception | No |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
}

const caster = createCaster<Example>().addString("s").build();

const myLittleObject: unknown = { s: "test" };

if (caster.isType(myLittleObject)) {
    // The type of the `myLittleObject` is now known.
    console.log(myLittleObject.s);
}

2. castTo<TYPE>(value: unknown) => TYPE

Returns the same object but with the narrowed type. (Throws error when the type of the input is not okay.)

| | | | ------------- | ------------------------------------- | | Input | Value to convert | | Result | Same value but with the narrowed type | | Exception | When the type of the value is wrong |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
}

const caster = createCaster<Example>().addString("s").build();

try {
    const value: Example = caster.castTo({ s: "test", n: 42 });
    // You can use `s` in the result, but there is no `n`
    console.log(`Value of s: ${value.s}`);
} catch {
    // Things can go wrong.
}

Warning:

  • The returned object can contain additional values

3. copyTo<TYPE>(value: unknown) => TYPE

Returns a copy of checked part of the input with the narrowed type. (Throws error when the type of the input is not okay.)

| | | | ------------- | ----------------------------------- | | Input | Value to convert | | Result | Copy of input | | Exception | When the type of the value is wrong |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
}

const caster = createCaster<Example>().addString("s").build();

try {
    const value: Example = caster.copyTo({ s: "test", n: 42 });
    // You can use `s` in the result, but there is no `n`
    console.log(`Value of s: ${value.s}`);
} catch {
    // Things can go wrong.
}

Warning:

  • The returned copy only contains the checked props (and nothing else)
  • Creating a copy costs extra memory usage and CPU time (can cause possible performance issues)

4. asyncCastTo<TYPE>(value: unknown) => Promise<TYPE>

The asynchronous version of the castTo(...) method. It does the same but with promises. Can be useful if you work with large object and don't want to block your app.

| | | | ------------- | ----------------------------------------------------------- | | Input | Value to convert | | Result | Copy of the value with the checked type (a promise) | | Exception | When the type of the value is wrong (in a promise like way) |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
}

const caster = createCaster<Example>().addString("s").build();

function doAsyncStuffs(): Promise<void> {
    try {
        const value = await caster.asyncCastTo({ s: "test" });
        console.log(`Value of s: ${value.s}`);
    } catch {
        // Don't forget: error can be thrown...
    }
}

Warning:

  • This method returns the same value but with the narrowed type, just like the original castTo(...)
  • There can be a lot of async calls in the background which can cause performance issues too

5. asyncCopyTo<TYPE>(value: unknown) => Promise<TYPE>

The asynchronous version of the copyTo(...) method. It does the same but with promises. Can be useful if you work with large object and don't want to block your app.

| | | | ------------- | ----------------------------------------------------------------------------- | | Input | Value to convert | | Result | Copy of the checked part of the input value with the checked type (a promise) | | Exception | When the type of the value is wrong (in a promise like way) |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
}

const caster = createCaster<Example>().addString("s").build();

function doAsyncStuffs(): Promise<void> {
    try {
        const value = await caster.asyncCopyTo({ s: "test" });
        console.log(`Value of s: ${value.s}`);
    } catch {
        // Don't forget: error can be thrown...
    }
}

Warning:

  • This method creates a copy of the checked part of the input, just like the original copyTo(...)
  • There can be a lot of async calls in the background which can cause performance issues too

Missing features on the casters

Async type guards and async assertions are not supported in TypeScript. (At least not yet. As far as I know.) So implementing a features like asyncIsType is unfortunatelly not an option.

How to build a caster?

You can do this with 3 easy steps:

  1. Call the createCaster<...>(...) function with the proper generic type
  2. Call the addXYZ(...) methods on the returned value.
  3. Call the build() at the end of the process.

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
    n: number;
    b: boolean;
}

const exampleCaster = createCaster<Example>().addString("s").addNumber("n").addBoolean("b").build();

Notes:

  • The best way to build a caster is this kind of call chain you can see in the example
  • The order of the addXYZ(...) methods is not important. Just be sure you called all of them!
  • You can only call the build() method after you did all the necessary calls to add your props to the caster builder. Before that the build() will simply not be available. (If there is a property s: string and you haven't added yet then you need to add an addString("s") before you can call the build().)
  • You will get compile errors related to never for the keys when you try to use the wrong addXYZ(...) method for a property.

Basic types

Methods to add a basic types (the input parameter is the key of the given property):

| Method | Supported type | | ----------------- | -------------- | | addString(KEY) | string | | addNumber(KEY) | number | | addBoolean(KEY) | boolean |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    s: string;
    n: number;
    b: boolean;
}

const result = createCaster<Example>().addString("s").addNumber("n").addBoolean("b").build();

Embedded

You can use the addCustom(..., ...) method to add a previously created caster for a given property. This means that you can embed the objects and the casters) into each other. The second parameter of the function is the caster you already have. (The first one is the key, as usual.)

| Method | Supported type | | ------------------------ | ---------------------------------------------- | | addCustom(KEY, CASTER) | The embedded object type with a builded caster |

Example:

import { createCaster } from "cast-as-trophy";

interface Inner {
    s: string;
}

interface Outer {
    i: Inner;
}

const innerCaster = createCaster<Inner>().addString("s").build();

const outerCaster = createCaster<Outer>().addCustom("i", innerCaster).build();

Arrays

You can use arrays of string, number, boolean and embedded objects of these. (Or object of object of these. And so on.)

| Method | Supported type | | ----------------------------- | ------------------------------------------------------- | | addStringArray(KEY) | Array<string> | | addNumberArray(KEY) | Array<number> | | addBooleanArray(KEY) | Array<boolean> | | addCustomArray(KEY, CASTER) | Array of the embedded object type with a builded caster |

Example:

import { createCaster } from "cast-as-trophy";

interface Inner {
    sa: string[];
    na: number[];
    ba: boolean[];
}

interface Outer {
    ia: Inner[];
}

const innerCaster = createCaster<Inner>().addStringArray("sa").addNumberArray("na").addBooleanArray("ba").build();

const outerCaster = createCaster<Outer>().addCustomArray("ia", innerCaster).build();

Optional (null and undefined)

At last but not least you can make the previous types optional with null and / or undefined

| Method | Supported type | | ---------------------------------------------- | ------------------------------------------ | | addStringOrUndefined(KEY) | string \| undefined | | addNumberOrUndefined(KEY) | number \| undefined | | addBooleanOrUndefined(KEY) | boolean \| undefined | | addCustomOrUndefined(KEY) | EmbeddedType \| undefined | | addStringArrayOrUndefined(KEY) | Array<string> \| undefined | | addNumberArrayOrUndefined(KEY) | Array<number> \| undefined | | addBooleanArrayOrUndefined(KEY) | Array<boolean> \| undefined | | addCustomArrayOrUndefined(KEY, CASTER) | Array<EmbeddedType> \| undefined | | addStringOrNull(KEY) | string \| null | | addNumberOrNull(KEY) | number \| null | | addBooleanOrNull(KEY) | boolean \| null | | addCustomOrNull(KEY) | EmbeddedType \| null | | addStringArrayOrNull(KEY) | Array<string> \| null | | addNumberArrayOrNull(KEY) | Array<number> \| null | | addBooleanArrayOrNull(KEY) | Array<boolean> \| null | | addCustomArrayOrNull(KEY, CASTER) | Array<EmbeddedType> \| null | | addStringOrNullOrUndefined(KEY) | string \| null \| undefined | | addNumberOrNullOrUndefined(KEY) | number \| null \| undefined | | addBooleanOrNullOrUndefined(KEY) | boolean \| null \| undefined | | addCustomOrNullOrUndefined(KEY) | EmbeddedType \| null \| undefined | | addStringArrayOrNullOrUndefined(KEY) | Array<string> \| null \| undefined | | addNumberArrayOrNullOrUndefined(KEY) | Array<number> \| null \| undefined | | addBooleanArrayOrNullOrUndefined(KEY) | Array<boolean> \| null \| undefined | | addCustomArrayOrNullOrUndefined(KEY, CASTER) | Array<EmbeddedType> \| null \| undefined |

Example:

import { createCaster } from "cast-as-trophy";

interface Example {
    su: string | undefined;
    nn: number | null;
    bnu: boolean | null | undefined;
}

const result = createCaster<Example>()
    .addStringOrUndefined("su")
    .addNumberOrNull("nn")
    .addBooleanOrNullOrUndefined("bnu")
    .build();

Not supported features for the caster builders

Union types are not supported

Except null and undefined, you can make other types optional with them.

You can not use something like this: string | number | boolean.

Array of arrays is not supported

Only the first level of arrays is available.

Array of unions is not supported

You can not use unions of types in the arrays. So Array<string | number> is not supported. (The Array<string | undefined> is not supported too.)

Tuples are not supported

You can't use tuples like [string] or [number, number]. Only arrays are supported, like this: string[].

Pure undefined and null are not supported

You can not use pure undefined or null for a property. And you can not use undefined[] and null[] array types either.

Index types are not supported

You can not use index types.

Using other exotic types like functions, symbols, etc. are not supported

You can not build caster for object with exotic types in it. (Including unknown and never.)

Using custom type guards are not supported

You can not embed your custom type guards.

Alternatives

If this library is not flexible enough for you then a good alternative can be the https://www.npmjs.com/package/ts-looks-like package.