Typescript,如何在向地图添加项目的两个类之间共享绑定的实用程序函数
假设我有两个类,我希望它们之间共享一个实用函数。该实用程序类访问作为对象类型映射的属性。地图中存储的对象类型对于每个类都是不同的。调用该函数时,该函数与调用它的类的实例绑定,并将它应添加到映射中的对象作为参数传递。过于简化的版本可能是这样的Typescript,如何在向地图添加项目的两个类之间共享绑定的实用程序函数,typescript,union-types,Typescript,Union Types,假设我有两个类,我希望它们之间共享一个实用函数。该实用程序类访问作为对象类型映射的属性。地图中存储的对象类型对于每个类都是不同的。调用该函数时,该函数与调用它的类的实例绑定,并将它应添加到映射中的对象作为参数传递。过于简化的版本可能是这样的 interface fooItem { name: string } interface barItem { name: string compact: boolean } function setItems(this: Foo
interface fooItem {
name: string
}
interface barItem {
name: string
compact: boolean
}
function setItems(this: Foo | Bar, item: fooItem | barItem) {
// Error here on 'item' arg
this.items.set(item.name, item);
}
class Foo {
constructor() {
this.items = new Map();
}
items: Map<string, fooItem>;
setItems = setItems.bind(this);
}
class Bar {
constructor() {
this.items = new Map();
}
items: Map<string, barItem>;
setItems = setItems.bind(this);
}
这样做的目的是让一个对象只与它关联的类一起使用,但我理解编译器如何不能保证它们是成对的
当类型为
Foo
时,让编译器知道项目将是类型fooItem
,反之亦然的正确类型脚本语法是什么?如果使用显式绑定函数而不是股票绑定,效果会更好,例如:
interface NamedItem {
name: string
}
interface HasNamedMap<T extends NamedItem> {
items: Map<string, T>;
}
function setItems<T extends NamedItem>(obj: HasNamedMap<T>): (item: T) => void {
return function(item: T) {
obj.items.set(item.name, item);
}
}
接口NamedItem{
名称:string
}
接口HasNamedMap{
项目:地图;;
}
函数集合项(obj:HasNamedMap):(项:T)=>void{
返回函数(项目:T){
对象items.set(item.name,item);
}
}
这样可以正确推断特定的“项目”类型:
class Foo {
items: Map<string, fooItem> = new Map();
setItems = setItems(this); // inferred as (item: fooItem) => void
}
class-Foo{
项目:Map=newmap();
setItems=setItems(this);//推断为(item:fooItem)=>void
}
要实现您要求的约束,我将创建如下函数:
function setItems<T extends { name: string }>(
this: { items: Map<string, T> },
item: T
) {
this.items.set(item.name, item); // okay
}
这是可行的,但比我喜欢的复杂得多
建议:既然您已经将函数值属性附加到Foo
和Bar
的每个实例,而不是使用原型,我将完全放弃这个
参数,只使用一个普通函数:
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);
}
const bindSetItems=
(ctx:{items:Map})=>
(item:N)=>ctx.items.set(item.name,item);
福班{
构造函数(){
this.items=newmap();
}
项目:地图;;
setItems=bindSetItems(本);
}
分类栏{
构造函数(){
this.items=newmap();
}
项目:地图;;
setItems=bindSetItems(本);
}
它的行为是相同的,但是它没有处理这个,而是使用curry而不是原型继承来完成任务
希望其中一个对你有用。祝你好运
像function setItems(this:{items:Map},item:T){this.items.set(item.name,item);}
这样的通用函数可以实现这一点,但是您会发现setItems.bind(this)
的结果的强类型不足以让您使用它。您可能需要一些手动注释或断言来进一步说明。
// 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);
}
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);
}