Memoized TimeSeries.fromJSON(...) for static or fetched data.
Re-parses only when key changes. If no key is provided, the input is
serialized via JSON.stringify as the cache key — fine for small to
moderate payloads. For large datasets, pass an explicit key (e.g. a fetch
URL or ETag) to avoid the serialization cost.
The schema generic S is inferred directly from input.schema (a plain
structural position), so an as const schema narrows the returned
TimeSeries<S> fully — result.column('cpu') resolves to Float64Column,
result.at(i)!.get('cpu') to number | undefined, etc. An earlier
two-generic <S, I extends Parameters<...>[0]> shape lost S through the
input-wrapper generic and collapsed schema-narrowed accessors to never
(the loose .get(string) path masked it); the column API surfaced it. The
accepted input type is unchanged — Parameters<fromJSON<S>>[0] already
resolved to TimeSeriesJsonInput<S> & { parse? } — so this is purely an
inference fix, not a surface change.
Memoized
TimeSeries.fromJSON(...)for static or fetched data.Re-parses only when
keychanges. If nokeyis provided, the input is serialized viaJSON.stringifyas the cache key — fine for small to moderate payloads. For large datasets, pass an explicitkey(e.g. a fetch URL or ETag) to avoid the serialization cost.The schema generic
Sis inferred directly frominput.schema(a plain structural position), so anas constschema narrows the returnedTimeSeries<S>fully —result.column('cpu')resolves toFloat64Column,result.at(i)!.get('cpu')tonumber | undefined, etc. An earlier two-generic<S, I extends Parameters<...>[0]>shape lostSthrough the input-wrapper generic and collapsed schema-narrowed accessors tonever(the loose.get(string)path masked it); the column API surfaced it. The accepted input type is unchanged —Parameters<fromJSON<S>>[0]already resolved toTimeSeriesJsonInput<S> & { parse? }— so this is purely an inference fix, not a surface change.