简体   繁体   English

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

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

i have this scenario: 我有这种情况:

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'
    }
  }
}

how do i express the constraint correct implementation of AbstractClass has to cover all properties from Contract interface ? 我如何表达约束正确的AbstractClass实现必须涵盖Contract接口的所有属性 simple solution is Impl implements Contract , but then i will have to duplicate declarations for all properties that do not have a complex logic getter. 简单的解决方案是Impl implements Contract ,但是我将不得不为没有复杂逻辑getter的所有属性复制声明。 so it would be nice to be able to also use inferred type of getBase() implementation. 所以能够使用推断类型的getBase()实现会很高兴。 the goal is to have a compile-time error if there is no value provided either on Impl itself or as property of inferred return type of getBase() . 如果在Impl本身上没有提供任何值或者作为推断返回类型getBase()属性,则目标是产生编译时错误。 is it possible in principle using Typescript? 是原则上可以使用Typescript吗?

If you make getBase abstract and specify that the return must be the difference of the properties of the current class and the interface, you will get a compile time error if the property is not in either the result of getBase or the class: 如果使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: "" 
        }
    }
}

You will notice that I had to pass the class itself as a type argumentto the base class, using the this type is not a solution as the keys of this are never fully known. 你会发现,我必须通过一类本身作为一种类型argumentto的基类,使用this类型不是解决方案的关键this是从来没有完全清楚。

Also getBase must return at the very least the difference between Impl and Contract but it could return more properties (typescript allows implementations to return a super type of the implementation method). 此外, getBase必须至少返回ImplContract之间的差异,但它可以返回更多属性(typescript允许实现返回实现方法的超类型)。 So if you have prop1 in both the class and the return of getBase it will not be an error. 因此,如果在类和返回的getBase都有prop1getBase它就不会出错。

Another solution is to add constraint for Impl class, and leave getBase return type inferred: 另一个解决方案是为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