链式调用中的打字稿类型

时间:2017-04-13 21:43:31

标签: typescript dependency-injection linked-list method-chaining

更新

  • 更好地解释我所寻求的内容
  • 我尝试的部分例子
  • 将问题减少到注射问题

我的问题

我正在尝试编写一些模式,允许对象在没有类继承的情况下扩展另一个对象,以实现松散耦合和函数方法(我在样本中用“extend”函数表示,也可能是称为“管道”)。这很容易。但所有这些都保留了打字。这很难。

我想知道如何按照流程获得Typescript类型。

以下是示例(link for Typescript playground)的简化代码段:

abstract class DecoratorAbstract {
    public parent: DecoratorAbstract;

    public extend<T extends DecoratorAbstract>(decorator: T): T {
        decorator.parent = this;
        return decorator;
    }

    abstract decorate(): {}
}

class InitialDecorator extends DecoratorAbstract {
    decorate() {
        return { var: 'value' } as { 'var': string };
    }
}

class Decorator1 extends DecoratorAbstract {
    decorate() {
        let result = this.parent.decorate();
        let newResult = Object.assign(result, { 'foo': 'foo' });
        return newResult;
    }
}

class Decorator2 extends DecoratorAbstract {
    decorate() {
        let result = this.parent.decorate();
        let newResult = Object.assign(result, { 'bar': 'bar' });
        return newResult;
    }
}

// Split to show the return types 
let initialDecorator = new InitialDecorator();
let r0 = initialDecorator.decorate();

let decorator1 = initialDecorator.extend(new Decorator1);
let r1 = decorator1.decorate();

let decorator2 = decorator1.extend(new Decorator2);
let r2 = decorator2.decorate();

console.log(r2);

// The syntax I seek
let someDecorator = new InitialDecorator()
    .extend(new Decorator1);
    .extend(new Decorator2);

let someResult = someDecorator.decorate();
// The type I seek:
// {var: string} & {foo: string} & {bar: string}

我得到的打字: {} & {'foo': string;}的{​​{1}}和r1的{​​{1}},将{} & {'bar': string;}的返回类型替换为r2(抽象函数的结果),而不是真实的类型。

所以我想知道:

  1. 我尝试做的是什么?
  2. 如果没有,为什么?
  3. 如果是的话,是否有一种解决方案,在语法上不太可怕(并遵循这个概念或接近的东西)
  4. 更新:我尝试过的事情

    有工厂

    decorator.parent.decorate

    使用一些 Piper 对象

    {}

    使用集合

    但是我的集合对象类型必须在开头就知道,并且对于所有项目都是相同的。也许我没有以正确的方式做到这一点。

    链接列表方法

    这是有效的:

    public extend<T extends DecoratorAbstract>(decoratorName: { new (): T }) {
       let decorator = new decoratorName();
       decorator.parent = this;
       return decorator;
    }
    

    我可以创建一个对象链并保留它们的类型。 但它没有那么多帮助...... 一旦遇到这个这个词,就不再遵循这些类型了(回到Abstract类)。

    到目前为止......

    我没有成功使 Typescript 保留我的对象类型。主要是因为:

    • 必须在对象声明
    • 上明确定义泛型类型
    • 类类型是特定的( Typescript 在分析返回类型时不遵循对象继承模型)

    我认为我的问题可以通过设计链接列表或集合的方式来解决,该列表可以保留每个元素的类型。

    更新:将问题减少到注射问题

    我认为我的尝试接近于解决方案......

    但我总是依赖的问题是以下(test it in Typescript playground):

    class Piper<T extends {parent: PARENT}, PARENT> {
        public obj: T;
        public parent: PARENT;
    
        constructor(obj: T, parent: PARENT) {
            this.obj = obj;
            this.obj.parent = this.parent as PARENT;
        }
    
        out(): T {
            return this.obj;
        }
    }
    

    问题很简单:我希望对象class Link<OBJ, PARENTLINK> { constructor(public obj: OBJ, public parent:PARENTLINK = null) {} pipe<NEWOBJ>(newObj: NEWOBJ):Link<NEWOBJ, this> { return new Link(newObj, this); } } abstract class DecoratorAbstract { abstract decorate<T>(result: T): {} } class InitialDecorator extends DecoratorAbstract { decorate<T>(result:T) { return { var: 'value' } as { 'var': string }; } } class Decorator1 extends DecoratorAbstract { decorate<T>(result:T) { let newResult = Object.assign(result, { 'foo': 'foo' }); return newResult; } } class Decorator2 extends DecoratorAbstract { decorate<T>(result:T) { let newResult = Object.assign(result, { 'bar': 'bar' }); return newResult; } } let l = new Link(new InitialDecorator); let l1 = l.pipe(new Decorator1); let l2 = l1.pipe(new Decorator2); 调用注入对象abstract class BaseObj<P> { parent: P abstract test(): {} } class A<P extends BaseObj<any>> extends BaseObj<P> { test() { return this.parent.test(); } } class B<P extends BaseObj<any>> extends BaseObj<P> { test() { return {hop: 'la'}; } } // let c = new A(); // Won't work let c = new A<B<any>>(); c.parent = new B; c.parent.test(); // return type: {hop: string} 的方法(在下面的例子中,嵌入的注入对象)。

    为了以一般方式可行:

    • A必须知道B的类型,否则会使用它扩展的类型
    • 为此,我必须能够指定泛型类型,或确保对象检测到它

    它适用于这个例子,因为一切都非常具体,但不是:

    A

    我想要的是一些允许注入类/对象的函数,这样:

    Blet c = new A<B<any>>(); c.parent = new B;

    问题在于我没有设法退出pipe(MyObj, new InjectedObj());函数let a = pipe(new MyObj(), new InjectedObj());的{​​{1}}实例,pipeA ...

    检测A<B<any>>条目中的类型不是问题。但让对象知道另一个(注入的)对象类型是我总是失败的地方......

    无论我写它的方式如何,都要回到这个问题上。

    我的尝试:

2 个答案:

答案 0 :(得分:1)

如果未在任何地方定义,则TypeScript无法知道返回类型a。如果要在运行时挂载管道,它只会在运行时知道它的类型。

如何将其定义为最终回报,例如A<B<any>>?它仍然可以调用A<string>,但最后,重要的是最终结果将是一个字符串。

B

答案 1 :(得分:0)

使用极简主义功能方法管理泛型可能更容易:

const decorate1 = <T>(item: T) => Object.assign({}, item, { b: 'b' })
const decorate2 = <T>(item: T) => Object.assign({}, item, { c: 'c' })
const multiDecorate = <T>(item: T) => decorate2(decorate1(item));

const initial = { a: 'a' };
const multiDecorated = multiDecorate(initial);

console.log({ multiDecorated });

Try it in TypeScript Playground

类型流过,因此multiDecorated是交集类型:

{} & { a: string; } & { b: string; } & { c: string; }
相关问题