Чтобы достичь требуемого ограничения, я бы сделал универсальную функцию, подобную следующей:
function setItems<T extends { name: string }>(
this: { items: Map<string, T> },
item: T
) {
this.items.set(item.name, item); // okay
}
Но вы найдете, если попытаетесь bind()
до this
, компилятор забудет, что item
уже {name: string}
, и вы получите что-то слишком слабо набранное, чтобы быть полезным само по себе.
Затем вам нужно будет вручнуюрасширить setItems
до конкретного типа для каждого класса:
// separate var with annotation
const fooSetItems: (this: Foo, item: fooItem) => void = setItems;
class Foo {
constructor() {
this.items = new Map();
}
items: Map<string, fooItem>;
setItems = fooSetItems.bind(this);
}
class Bar {
constructor() {
this.items = new Map();
}
items: Map<string, barItem>;
// same var with assertion
setItems = (setItems as (this: Bar, item: barItem) => void).bind(this);
}
Это работает, но сложнее, чем мне нравится.
Предложение вместо этого: так как вы ужеПрикрепляя функционально-значимые свойства к каждому экземпляру Foo
и Bar
вместо использования прототипа, я бы полностью отказался от this
параметров и просто использовал бы простую функцию:
const bindSetItems =
<N extends { name: string }>(ctx: { items: Map<string, N> }) =>
(item: N) => ctx.items.set(item.name, item);
class Foo {
constructor() {
this.items = new Map();
}
items: Map<string, fooItem>;
setItems = bindSetItems(this);
}
class Bar {
constructor() {
this.items = new Map();
}
items: Map<string, barItem>;
setItems = bindSetItems(this);
}
Этоведет себя так же, но вместо того, чтобы возиться с this
, он просто использует карри вместо прототипического наследования для выполнения работы.
Надеюсь, одна из тех работ для вас. Удачи!
Ссылка на код