[英]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
必须至少返回Impl
和Contract
之间的差异,但它可以返回更多属性(typescript允许实现返回实现方法的超类型)。 So if you have prop1
in both the class and the return of getBase
it will not be an error. 因此,如果在类和返回的getBase
都有prop1
, getBase
它就不会出错。
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.