@mantlebee/ts-data
    Preparing search index...

    Type Alias IDataSource<TItem, TExt>

    Reads items through a reader, letting its extensions shape the query and the result. See IDataSourceExtension for the read cycle.

    Extensions in the type. TExt is the record of the extensions of the source, by key (DataSourceExtensionsDefinition), the way the events of a Subscribable of ts-core are a record. Every key whose value cannot be undefined is a required readonly property, every key whose value may be undefined is an optional one, to narrow on; a key not in the record is not a property. The data source knows no key: the extensions of the package are named through IDataSourceWith (IDataSourceWith<User, "filtering" | "pagination">), the shortcut for the record of their interfaces. A source with more extensions is assignable to a parameter asking for fewer, never the opposite, and the default, an empty record, guarantees nothing. createDataSource infers TExt from the record it is given, custom keys included: no registration anywhere.

    This is a type alias, not an interface: TypeScript does not let an interface extend a mapped type over a generic record. Extend or implement it with concrete type arguments only; IDataSourceBase holds the members that do not depend on the extensions.

    The latest read wins: a read() requested while another is running supersedes it. The superseded read() rejects with the AbortedException of ts-core at once, its result is discarded (no items, no error), and items always hold the result of the latest completed read.

    Type Parameters

    function bindGrid(source: IDataSourceWith<User, "filtering" | "pagination">) {
    source.filtering.addFilter(adult); // guaranteed by the type
    source.pagination.goToNextPage();
    }
    const users = createDataSource(readUsers, { filtering, pagination, sorting, distinct });
    bindGrid(users); // more extensions than asked: fits
    users.distinct; // DistinctExtension<User>, a custom key
    users.on("items", (items) => render(items));
    users.read().catch((error) => {
    if (!isAbortedException(error)) throw error; // superseded: nothing to do
    });