I'm running into a problem writing Typescript definitions for a third-party script that's using React PropTypes's instanceof check. Specifically React TimeSeries Charts and PondJS. (They don't have any created yet, which is why I'm under-taking it).
I've defined a Type file for Pond that looks like this
declare module 'pondjs' {
type Timestamp = number;
/* other type aliases */
export class TimeSeries {
constructor(
options: {
[index: string]: any;
}
);
static is: (arg1: TimeSeries, arg2: TimeSeries) => boolean;
range: () => any;
min: (key: string) => number;
max: (key: string) => number;
name: () => any;
atTime: (timestamp: Timestamp) => any;
/* Other methods */
}
/* Other Class Definitions */
}
This is then used by my wrapper class something like this
import { TimeSeries } from 'pondjs';
import { ChartContainer, ChartRow, LineChart } from 'react-timeseries-charts';
const timeSeries: TimeSeries = new TimeSeries({events: [{value: 15}]});
class myWrapper extends React.Component<Props, {}> {
render() {
return (
<ChartContainer>
<ChartRow>
<LineChart series={timeSeries} />
</ChartRow>
</ChartContainer>
);
}
This is an extremely reduced example, but my real code all works correctly, draws the correct thing to the page, and Typescript fails to compile if I pass incorrect parameters.
However, I'm getting a bunch of errors from PropTypes thrown from PropType's createInstanceTypeChecker
.
"Warning: Failed prop type: Invalid prop `series` of type `TimeSeries` supplied to `LineChart`, expected instance of `TimeSeries`."
The problem is that LineChart
checks series: propTypes.instanceof(TimeSeries)
, but it's of course internally importing Pond and checking against the "real" TimeSeries
, not the one that has come through my Typescript type module definition.
When I step inside createInstanceTypeChecker to see what's going on, I can see that even though they're technically not the same class, (so I guess PropTypes is justified in its error) they are the same for all practical purposes, which is what I would expect Typescript to have produced.
> expectedClass === props[propName].constructor
false
> props[propName] instanceof expectedClass
false
> props[propName].constructor
ƒ TimeSeries(arg) {
(0, _classCallCheck3.default)(this, TimeSeries);
this._collection = null;
// Collection
this._data = null;
// Meta data
if (arg ins…
> expectedClass
ƒ TimeSeries(arg) {
(0, _classCallCheck3.default)(this, TimeSeries);
this._collection = null;
// Collection
this._data = null;
// Meta data
if (arg ins…
However, I would still expect that instanceof check to be true if Typescript is doing what I thought it did, something like the following
import { TimeSeries as _ts } from 'pondjs';
export class TimeSeries extends _ts {
/* same class, but with type extensions */
}
I suppose React TimeSeries Charts could "solve" by checking the shape of the prop instead of the specific constructor used. However, this must also be a very common issue when adding type definitions for third party libs, right? Since I can't find similar bug reports anywhere, I suspect I must be missing something obvious.
I don't want to disable PropTypes completely. I'd either like to find out I'm misconfiguring this type declaration file and change it so PropTypes checking instanceof works, or be able to update React TimeSeries Charts with a different equally simple check that PropTypes could do to convince itself the Typescript-enhanced classes are still essentially the same class, without resorting to comparing the shape key by key.
Versions:
- Typescript 2.5.0
- React 15.6.1
- Proptypes 15.5.10
- PondJS 0.8.7
- React TimeSeries Charts 0.12.8