DataSource class, to be extendedVersion 2.2.0 exports the DataSource class again, for inheritance: a
source with members of its own extends it instead of implementing
IDataSource from scratch. The release is additive: no existing export
changes, and createDataSource stays the way to build a source.
2.0.0 stopped exporting the class because a class cannot type its members
from a generic record: new DataSource(reader, { filtering }) exposes no key
in its type, where createDataSource(reader, { filtering }) infers every
one. That still holds, and the factory is still the way to build a
source. What the factory cannot do is give a source members of its own (a
readAdults(), an overridden read()): that takes the class, and
reimplementing the read cycle ("the latest read wins", the two phases, the
events) behind IDataSource to get it is not an option. The class is
exported to be extended.
A subclass knows its extensions, so it types the keys the class cannot: one
declare readonly per key given to super.
class UsersDataSource extends DataSource<User> {
declare public readonly filtering: FilterExtension<User>;
declare public readonly pagination: PaginationExtension<User>;
public constructor() {
super(readUsers, {
filtering: new FilterExtension<User>(),
pagination: new PaginationExtension<User>(countUsers, 20),
});
}
public async readAdults(): Promise<void> {
this.filtering.setFilters([adult]);
await this.read();
}
}
useTable(new UsersDataSource()); // fits IDataSourceWith<User, "filtering" | "pagination">
declare is required. The keyed properties are own properties set by
the constructor of the class. declare emits nothing; a plain field
(public readonly filtering!: FilterExtension<User>) is redefined to
undefined after super returns, under useDefineForClassFields, the
default from the ES2022 target on. Nothing warns: the key is not a member
of the base class, so the compiler sees no conflict.super:
the subclass keeps the two in line._extensions, every extension given,
in the order of the keys), the reader (_reader) and the _eventBus of
Subscribable. The read cycle itself stays private: override read() or
dispose() around super.items or read.A subclass adding behaviour to any source knows no key. Give it a factory of
its own, typed like createDataSource:
class CountingDataSource<TItem> extends DataSource<TItem> {
public readsCount = 0;
public override async read(): Promise<void> {
this.readsCount++;
await super.read();
}
}
function createCountingDataSource<
TItem,
TExt extends DataSourceExtensionsDefinition<TItem>,
>(reader: DataSourceReader<TItem>, extensions: TExt) {
return new CountingDataSource<TItem>(
reader,
extensions,
) as CountingDataSource<TItem> & DataSourceExtensionProperties<TExt>;
}
const users = createCountingDataSource(readUsers, { filtering, sorting });
users.sorting; // SortExtension<User>
users.readsCount; // number
New, from the package root: DataSource. Nothing else changes.
npm install @mantlebee/ts-data@^2.2.0
Nothing to migrate. Keep building the sources with createDataSource; extend
DataSource where a source needs members of its own.