I'm trying to create a TypeScript class that is initialized with an object and has a method which can only take keys of that object as arguments. So:
class MyClass {
properties = {};
constructor(properties) {
this.properties = properties;
}
// Passed propNames should only be keys of this.properties
pick(...propNames) {
return propNames.reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {});
}
}
This seems similar to this problem, but I can't figure out how to apply it in this case, since the properties are passed in from the outside.
const props = { key: 'value', key2: 'value2' };
interface PropKeys {
key: string;
key2: string;
}
type KeyName = keyof(PropKeys);
// But what do I do to the class to get this to work?
const instance = new MyClass(props);
instance.pick('key', 'key2'); // Great
instance.pick('key3'); // Should throw a type error
Is this possible? Is there a way to do it without explicitly defining the InstanceKeys, but instead deriving them from the props passed while initializing the instance?
I'm trying to wrap my head around generics, and was thinking maybe something like this:
class MyClass {
properties = {};
constructor<Type>(properties: Type) {
this.properties = properties;
type TypeKeys = keyof(Type);
}
pick(...propNames: TypeKeys[]) {
return propNames.reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {});
}
}
But this raises two type errors:
- On the
<Type>: "Type parameters cannot appear on a constructor declaration." - On the
TypeKeys[]: "Cannot find name 'TypeKeys'." (I mean, makes sense; it's out of scope.)
UPDATE: This feels closer, but I'm running into an issue where the properties are first defined on the class (above the constructor):
class MyClass<PropType extends Properties> {
properties: PropType = {};
constructor(properties: PropType) {
this.properties = properties;
}
pick(...propNames: Array<keyof(PropType)>) {
return propNames.reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {});
}
}
The TS error I'm running into on that line is
Type '{}' is not assignable to type 'PropType'. '{}' is assignable to the constraint of type 'PropType', but 'PropType' could be instantiated with a different subtype of constraint 'Properties'
The issue here is that any properties passed in may have their own keys, but must be instances of type Properties, which constrains the values.