Objects.structure()

Syntax

function structure<T extends Structure>(object: object, struct: T): object is MappedStructure<T>

Type guard that checks if an object conforms to the given shape.

Parameters
object

The object to perform the structural check on.

struct

A valid Structure object that determines the desired shape of the object.

exhaustive Optional

If true, the check is exhaustive, that is, all properties of object must match a corresponding property on struct. If either argument contains keys that the other argument does not have, the check fails.

This is false by default, so the check will succeed even if struct has properties that object does not, as long as object has all properties of struct.

Example 1

import { Objects, Structure } from 'potence';
import { oneOf, string, number, nullish, instanceOf } from 'potence/fluent/matchers';
import { fetchJson } from 'api.ts';

// Assume you have a function that fetches some JSON from a web API.
// Since the JSON comes from an endpoint you have no control over, you can't
// be sure of its type.

// Note: normally this would be an asynchronous function, however for the sake
// of simplicity let's assume the fetch is a blocking call.
const obj: object = fetchJson();

// Define the shape of the expected JSON.
// It is recommended you define your Structures in another file and import them
// (rather than defining them inline).
const shape: Structure = {
    results: [{
        mandatoryProp: string(),
        optionalProp: oneOf(number(), nullish())
    }],
    offset: number()
};

// Check whether obj conforms to shape.
if (Objects.structure(obj, shape)) {
    let sum: number = 0;

    obj.results.forEach(result => {               // no error, obj.results is of type array
        if (result.mandatoryProp === 'myProp') {  // no error, result.mandatoryProp is of type string
            sum += result.optionalProp;           // error, optionalProp may be undefined
        }
    });
}

Example 2

import { Objects } from 'potence';

class Owner { ... }

interface Animal {
    name: string;
    owner?: Owner;
    pastOwners: Owner[];
}

function isAnimal(obj: unknown): obj is Animal {
    return isObject(obj) && Objects.structure(obj, {
        name: number(),
        owner: oneOf(instanceOf(Owner), nullish()),
        pastOwners: arrayOf(instanceOf(Owner))
    });
}

Remarks

Due to the fact that this function is a type guard, this makes it an extremely powerful tool for quickly checking whether an unknown object contains a known set of properties of a known type. As long as you use this function properly, you should never have to manually cast a value to another type as TypeScript will understand that the source object corresponds to the passed object structure if the return type is true.

The function can also be especially useful for use in a user-defined type guard, as seen in Example 2 above, even though you lose the advantages of Objects.structure()’s own type guard this way.

See Structure for detailed information on the Structure type as well as a complete example showing all possible values.