typescript:具有原始类型约束的泛型类型

我在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
    }
}()

但我不知道为什么会出现这个错误 Class '(Anonymous class)' incorrectly extends base class 'Column'. Types of property 'getValue' are incompatible. Type '(value: number) => number' is not assignable to type '(value: number) => S'. Type 'number' is not assignable to type 'S'

回答(2)

2 years ago

Column 上,getter和setter S 不一定是同一类型,因此您应该将类型参数移动到其父类: 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
    }
}()

至少在has no errors之上的版本 .

我知道您可能想要从您使用setter的任何类型推断 SColumn 必须在实例化时具有良好定义的类型,因此这意味着您在调用构造函数时显式(即 new Column<UserId, number>(...) )或添加 S param在构造函数中所以 S 可以从它推断出来(比如 new Column<UserId>('id', 123)

2 years ago

您的 getValue 使用泛型 S ,因此,继承的实现也必须使用 S .

let id = new class extends Column<UserId> {
    constructor() { super("id") }
    public getValue<S extends Primative>(value: UserId): S {
        return <S>value
    }
}()

如果将 S 带到类中,则可以将函数缩小到 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
    }
}()