【问题标题】:Default generic type in typescript打字稿中的默认泛型类型
【发布时间】:2018-07-04 13:39:13
【问题描述】:

所以我有一个量角器列表页面对象。该对象默认返回 ElementFinder 实例,但可以自定义为返回 ComplexType 实例,如下所示:

class ComplexType {
  foo = 'foo';

  constructor(public element: ElementFinder) {}
}

const list = new List<ComplexType>({ element: ..., type: ComplexType});
expect(list.get(0).foo).toBe('foo');

这是页面对象定义:

import { ElementFinder } from 'protractor';

export interface ListItem<T> {
  new(element: ElementFinder): T;
}

export interface ListOptions<T> {
  element: ElementFinder;
  selector?: string;
  type?: ListItem<T>;
}

export class List<T = ElementFinder> {
  public readonly element: ElementFinder;
  private selector: string;
  private type: (element: ElementFinder) => T;

  get items() {
    return this.element.$$(this.selector);
  }

  get length() {
    return this.items.count();
  }

  constructor(options: ListOptions<T> | ElementFinder, selector?: string) {
    if (options instanceof ElementFinder) {
      this.element = options;
      this.selector = selector || 'li';
      this.type = (element: ElementFinder) => element;
    } else {
      this.element = options.element;
      this.selector = options.selector || 'li';
      this.type = (element: ElementFinder) => new options.type(element);
    }
  }

  get(index: number): T {
    return this.type(this.items.get(index));
  }
}

我遇到的问题是打字稿不理解 T 有时是 ElementFinder。因此,当我返回 ElementFinder 的一个实例时,它会抱怨元素查找器与 T 不匹配。

我被难住了。这肯定有可能吗?

【问题讨论】:

    标签: typescript protractor


    【解决方案1】:

    问题是在类中,T 不知道是什么特定的(即使您进行一些检查,编译器也不会以任何方式缩小T)。这意味着所有分配都必须适用于任何可能的T,并且由于this.type = (element: ElementFinder) =&gt; element; 不适用于任何T,它会给出错误。

    如果我们确定这是误报,那么快速而肮脏的解决方法是使用类型断言:

    this.type = (element: ElementFinder) => element as any;
    

    更优雅的解决方案是将type 更改为必需,并传入适当的函数:

    class ComplexType {
        foo = 'foo';
    
        constructor(public element: ElementFinder) { }
    }
    
    export interface ListOptions<T> {
        element: ElementFinder;
        selector?: string;
        type: (element: ElementFinder) => T;
    }
    
    export class List<T = ElementFinder> {
        public readonly element: ElementFinder;
        private selector: string;
        private type: (element: ElementFinder) => T;
    
        get items() {
            return this.element.$$(this.selector);
        }
    
        get length() {
            return this.items.count();
        }
        public static default(element: ElementFinder, selector = 'li') :ListOptions<ElementFinder>{
            return {
                element,
                selector,
                type : (e) => e
            }
        }
        constructor(options: ListOptions<T>, selector?: string) {
            this.element = options.element;
            this.selector = options.selector || 'li';
            this.type = options.type;
        }
    
        get(index: number): T {
            return this.type(this.items.get(index));
        }
    }
    let element!: ElementFinder;
    
    // complex usage
    const list1 = new List<ComplexType>({ element, type: e=> new ComplexType(e) });
    //default usage
    const list2 = new List(List.default(element));
    

    【讨论】:

    • 感谢您的解释!
    猜你喜欢
    • 1970-01-01
    • 2019-02-27
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    • 2020-06-29
    • 1970-01-01
    相关资源
    最近更新 更多