I currently have a class structure that resembles the following:
class BasicType {
coerce(value) {
return String(value);
}
read(value) {
return this.coerce(value);
}
}
The coerce
method consistently returns a string, while the read
method may return various types depending on the subclass. For instance:
class FloatType extends BasicType {
read(value) {
return Number(super.read(value));
}
}
I am attempting to implement this in TypeScript but am encountering difficulties. I believe I need to utilize generics for this functionality, but my initial attempts were not successful.
class BasicType<T = string> {
coerce(value: any): string {
return String(value);
}
read(value: any): T {
return this.coerce(value);
// Type 'string' is not assignable to type 'T'.
// 'T' could be instantiated with an arbitrary type unrelated to 'string'
// ts(2322)
}
}
class FloatType<T = number> extends BasicType<T> {
read(value: any): T {
return Number(super.read(value));
// Type 'number' is not assignable to type 'T'.
// 'T' could be instantiated with an arbitrary type unrelated to 'number'.
// ts(2322)
}
}
This becomes more complex when subclassing the subclass.
class IntegerType<T = number> extends FloatType<T> {
read(value: any): T {
return Math.floor(super.read(value));
// `return`
// Type 'number' is not assignable to type 'T'.
// 'T' could be instantiated with an arbitrary type unrelated to 'number'.
// ts(2322)
// `super.read(value)`
// Argument of type 'T' is not assignable to parameter of type 'number'.
// ts(2345)
}
}
What mistakes am I making here? How can I instruct TypeScript that FloatType#read
returns a number so it can be used in IntegerType#read
as intended?