Reputation: 115
I have the following generic classes in TypeScript
type UserId = number
type Primitive = string | number | boolean
class ColumnValue<T, S extends Primitive> {
constructor(public columnName: String, public value: S) { }
}
abstract class Column<T> {
constructor(public columnName: String) { }
public set<S extends Primitive>(value: T): ColumnValue<T, S> {
return new ColumnValue(this.columnName, this.getValue(value))
}
public abstract getValue<S extends Primitive>(value: T): S
}
let id = new class extends Column<UserId> {
constructor() { super("id") }
public getValue(value: UserId): number {
return value
}
}()
But I don't know why get this error:
Class '(Anonymous class)' incorrectly extends base class 'Column<number>'.
Types of property 'getValue' are incompatible.
Type '(value: number) => number' is not assignable to type '<S extends Primitive>(value: number) => S'.
Type 'number' is not assignable to type 'S'
Upvotes: 5
Views: 6706
Reputation: 13240
On Column
getter and setter S
isn't necessarily the same type so you should move the type param to its parent class: Column<T, S extends Primitive>
.
type UserId = number
type Primitive = string | number | boolean
class ColumnValue<T, S extends Primitive> {
constructor(public columnName: String, public value: S) { }
}
abstract class Column<T, S extends Primitive> {
constructor(public columnName: String) { }
public set(value: T): ColumnValue<T, S> {
return new ColumnValue(this.columnName, this.getValue(value))
}
public abstract getValue(value: T): S
}
let id = new class extends Column<UserId, number> {
constructor() { super("id") }
public getValue(value: UserId): number {
return value
}
}()
The version above has no errors at least.
I understand that you probably want to infer the S
from whatever type you use with you setter but Column
must have a well defined type upon instantiation, so that means that you either explicit when calling the constructor (that is new Column<UserId, number>(...)
) or add a S
param in the constructor so S
can be inferred from it (like in new Column<UserId>('id', 123)
)
Upvotes: 4
Reputation: 2848
Your getValue
uses a generic S
, so, the inherited implementation must use S
as well.
let id = new class extends Column<UserId> {
constructor() { super("id") }
public getValue<S extends Primative>(value: UserId): S {
return <S>value
}
}()
If you take the S
to the class, your function can be narrowed to number
.
abstract class Column<T, S extends Primative> {
constructor(public columnName: String) { }
public set(value: T): ColumnValue<T, S> {
return new ColumnValue(this.columnName, this.getValue(value))
}
public abstract getValue(value: T): S
}
let id = new class extends Column<UserId, UserId> {
constructor() { super("id") }
public getValue(value: UserId): number {
return value
}
}()
Upvotes: 1