Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript,如何在向地图添加项目的两个类之间共享绑定的实用程序函数_Typescript_Union Types - Fatal编程技术网

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);
}