Reputation: 1651
I am looking for a way to correctly express my data model with tyepscript definitions. So far I have the following:
type Data = Record<string, string>;
interface DataContainer<D extends Data> {
id: string;
data: D;
}
interface Context {
dataContainers: DataContainer<any>[];
}
A Context
stores a set of DataContainers
, where each DataContainer
is generic over a specific data structure D
. Now what I want to express is that each of those data structures D
should follow a universal type Data
. I.e. consisting of arbitrary but fixed <string, string>
pairs.
I really could not find a proper solution for that, the best thing I found was DataContainer<D extends Data>
. Do you think that's a good approach?
At least the following gives my a linting error as desired:
interface MyData extends Data {
x: "1",
y: 2, // Lint error, because not string. (As I want it)
}
So I conclude that when writing <D extends Data>
it would also not be allowed for D
to have an entry like y: 2
, correct?
Now a real problem for me is that the following does not give me a linting error:
const myContext: Context = {
dataContainers: [
{
id: "123",
data: {
x: 1, // This should be marked by the linter
y: "2",
z: {a: 1}, // This also
}
}
]
}
I am looking for a way to model my definitions such that a linter would mark this as invalid, because there exists no D
such that the above would be a valid Context. Is that possible? Thanks for your help!
Upvotes: 0
Views: 157
Reputation: 249546
You are close. The issue is with DataContainer<any>
. Any effectively turns off type checking where it is used. This means that since data
in DataContainer<any>
will be of type any
, no checks will be done for the property. This is regardless of the constraint you put on D
The simple solution is to not use any
, use the constraint as the type argument to DataContainer
:
interface Context {
dataContainers: DataContainer<Data>[];
}
Upvotes: 1