使用类作为模板或参数?

时间:2018-10-24 02:40:52

标签: typescript

假设我想要一个类字典,这样我就可以管理局部唯一的类(每个类字典实例)。

class A { }

class ClassDict {
    kvp: { [k:string]: any }; // not sure if there is better way
}

b = new ClassDict()

我尝试实现以下方法,但这似乎是多余的:

// call as b.add<A>(new A())
public add<T>(t: T): T {
  this.kvp[t.name] = t;
  return t;
}

// call as b.get<A>(A)
public get<T>(t: any): T {
  return this.kvp[t.name] as any as T;
}

如果仅在模板中使用类,则无法调用.name来获取密钥。

如果仅使用class作为参数,则无法声明返回类型。

我希望我可以这样打电话:

// creates an object of A
// since param is instance of A, it is supposed to know it
b.add(new A())

// updates an object of A
// same as add
b.update(new A())

// returns an object of A
b.get(A);
// or
b.get<A>()

// removes an object of A, this might be easier as it returns void
b.remove(A)
// or
b.remove<A>()

我该如何实现?预先感谢。

2 个答案:

答案 0 :(得分:1)

我们将class A作为new()=>A。所以你必须给get<T>(t: new()=>T)

这是它在打字稿中的完成方式:

class A {
}

class ClassDict {
    kvp: { [k: string]: any } = {};

    public add<T>(t: T){
        this.kvp[t.constructor.name] = t;
    }
    public get<T>(t: new()=>T) {
        return this.kvp[t.name] as T;
    }
    public update<T>(t:T) {
        this.kvp[t.constructor.name] = t;
    }
    public remove<T>(t: new()=>T) {
        this.kvp[t.name] = undefined;
    }
}
let b = new ClassDict()

b.add<A>(new A())
let d = b.get(A); // typeof d is A
b.update(new A())
b.remove(A)

您可以在Typescript Playground here看到实时工作。发表评论,以备不时之需。

更新

ES6附带了函数的.name属性。因此,为了使打字稿知道这一点,您必须在配置中包括最新的库:

tsc test.ts --lib 'dom','es2018'

使用--lib时,您必须指定打字稿应使用的所有库,包括隐式使用的默认库,此处需要明确提及。

答案 1 :(得分:0)

我更改了add仅支持构造函数的API。 ({updateremove被省略,因为它们相同)

type ComponentConstructor<C extends IComponent> = new (e: IEntity) => C;

class Entity implements IEntity {
    protected _components: { [k: string]: IComponent };

    public AddComponent<C extends IComponent>(ctor: ComponentConstructor<C>): C {
      const k = (ctor as any).name;
      if (this._components[k] === undefined) {
        const c = new ctor(this);
        this._components[k] = c;
      } else {
        console.warn(k + ' already exists.');
      }
      return this._components[k] as C;
    }

    public GetComponent<C extends IComponent>(ctor: ComponentConstructor<C>): C {
      const k = (ctor as any).name;
      return this._components[k] as C;
    }
}

// user case
class MyE extends ecs.Entity { }
class MyC extends ecs.Component { }

const e = new MyE();
const c = e.AddComponent(MyC);
e.GetComponent(MyC);