繁体   English   中英

使用推断方法返回类型的Typescript泛型约束

[英]Typescript generic constraint that uses inferred method return type

我有这种情况:

abstract class AbstractClass<T> {
  abstract getData(): T;
  getBase(): Partial<T> {
    return {};
  }
}

interface Contract {
  prop1: string;
  prop2: string;
}

class Impl extends AbstractClass<Contract> {
  get prop1() {
    // some complex logic here
    return '';
  }

  getBase() {
    return {
      prop2: 'foo'
    }
  }
}

我如何表达约束正确的AbstractClass实现必须涵盖Contract接口的所有属性 简单的解决方案是Impl implements Contract ,但是我将不得不为没有复杂逻辑getter的所有属性复制声明。 所以能够使用推断类型的getBase()实现会很高兴。 如果在Impl本身上没有提供任何值或者作为推断返回类型getBase()属性,则目标是产生编译时错误。 是原则上可以使用Typescript吗?

如果使getBase abstract并指定返回必须是当前类和接口的属性的差异,那么如果属性不在getBase或类的结果中,则会出现编译时错误:

abstract class AbstractClass<T, TThis> {
    abstract getBase(): { [P in Exclude<keyof T, keyof TThis>]: T[P] };
}
interface Contract {
    prop1: string;
    prop2: string;
}

class Impl extends AbstractClass<Contract, Impl> {
    get prop1() {
        // some complex logic here
        return '';
    }

    getBase() {
        return {
            prop2: ""
        }
    }
}

class ImplWrong  extends AbstractClass<Contract, ImplWrong> {
    get prop1() {
        // some complex logic here
        return '';
    }

    getBase() { // error Property 'getBase' in type 'ImplWrong' is not assignable to the same property in base type
        return {
            prop3: "" 
        }
    }
}

你会发现,我必须通过一类本身作为一种类型argumentto的基类,使用this类型不是解决方案的关键this是从来没有完全清楚。

此外, getBase必须至少返回ImplContract之间的差异,但它可以返回更多属性(typescript允许实现返回实现方法的超类型)。 因此,如果在类和返回的getBase都有prop1getBase它就不会出错。

另一个解决方案是为Impl类添加约束,并保留getBase返回类型:

abstract class AbstractClass<T> {
  abstract getData(): T;
  getBase(): Partial<T> {
    return {};
  }
}

interface Contract {
  prop1: string;
  prop2: string;
}


type ImplConstraint<T, I extends AbstractClass<T>> = 
  { [n in Exclude<keyof T, keyof ReturnType<I['getBase']>>]: T[n] };

class Impl extends AbstractClass<Contract> implements ImplConstraint<Contract, Impl>  {
  get prop1() {
    // some complex logic here
    return '';
  }

  getBase() {
    return {
      prop2: 'foo'
    }
  }

  getData(): Contract {
       return {} as Contract;    
  }  

}

class ImplWrong extends AbstractClass<Contract> implements ImplConstraint<Contract, ImplWrong>  {

// Class 'ImplWrong' incorrectly implements interface 
//  'ImplConstraint<Contract, Impl>'
//       Property 'prop1' is missing in type 'ImplWrong'.

  get prop11() {
    // some complex logic here
    return '';
  }

  getBase() {
    return {
      prop2: 'foo'
    }
  }

  getData(): Contract {
       return {} as Contract;    
  }  

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM