Я пытаюсь создать класс TypeScript, который инициализируется объектом и имеет метод, который может принимать только ключи этого объекта в качестве аргументов. Так:
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]
}), {});
}
}
Это похоже на Эта проблема, но я не могу понять, как его применить в этом случае, так как свойства передаются извне.
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
Это возможно? Есть ли способ сделать это без явного определения InstanceKeys, а вместо этого получить их из реквизитов, переданных при инициализации экземпляра?
Я пытаюсь обернуть голову вокруг дженериков и подумал, может быть, что-то вроде этого:
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]
}), {});
}
}
Но это вызывает две ошибки типа:
<Type>: «Параметры типа не могут отображаться в объявлении конструктора».TypeKeys[]: «Не удается найти имя TypeKeys». (Я имею в виду, имеет смысл; это выходит за рамки.)ОБНОВИТЬ: Это кажется ближе, но я столкнулся с проблемой, когда свойства сначала определяются в классе (над конструктором):
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]
}), {});
}
}
Ошибка TS, с которой я сталкиваюсь в этой строке,
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'
Проблема здесь в том, что любой переданный properties может иметь свои собственные ключи, но должен быть экземпляром типа Properties, который ограничивает значения.






Ваш общий тип должен идти в объявлении class, а не в его конструкторе. Тогда keyof Type должен быть анонимным типом. Вам также нужно ввести properties, чтобы TypeScript знал, что его можно индексировать с помощью keyof Type, что я и сделал в этом примере, присвоив ему тип Partial<Type>.
Я также использовал утверждение типа, чтобы начальный объект {} вашего reduce был типизирован как Partial<Type>, поэтому TypeScript поймет, как его индексировать после его создания.
class MyClass<Type> {
properties: Partial<Type> = {};
constructor(properties: Type) {
this.properties = properties;
}
pick(...propNames: (keyof Type)[]) {
return propNames.reduce((obj, name) => ({
...obj,
[name]: this.properties[name]
}), {} as Partial<Type>);
}
}