对于第一个问题,你的方法在
V
参数上存在问题,因为你指定了它的默认值,但这并不意味着
V
必须扩展
T[P]
,只是这是默认值,你可以使用任何类型参数来调用构造函数。在适当的地方使用
T[P]
,即使你正确地限制了它 (
V extends T[P] = T[P]
),编译器仍然无法正确地跟踪
V
是否可分配给
T[P]
。
export class ModelProperty<T, P extends keyof T> {
constructor(public name: P, public value: T[P]) { }
fun(t: T){
let value = t[this.name];
}
}
关于您提到的第二个问题,这是类型参数和推断方式的不幸副作用。如果您为泛型参数指定了默认值,则该默认值将被使用,并且不会进行推断。如果您不为 K
指定默认值,则无法仅指定 T
的值,还必须指定 K
。简单的解决方法是使用两个函数的方法:
export class ModelProperty<T, P extends keyof T> {
constructor(public name: P, public value: T[P]) { }
static for<T>() {
return function <P extends keyof T>(name: P, value: T[P]){
new ModelProperty<T, P>(name, value);
}
}
}
const carModelCreator = ModelProperty.for<Car>();
let engine2 = carModelCreator('engine','22');
let engine1 = carModelCreator('engine',2);
关于嵌套路径的第三个问题,类不能有可变数量的类型参数,因此您可以选择为每个路径长度创建专用类。
export class ModelProperty2<T, P extends keyof T, P2 extends keyof T[P]> {
constructor(public name: [P, P2], public value: T[P][P2]) { }
static for<T>() {
return function <P extends keyof T, P2 extends keyof T[P]>(name: [P, P2], value: T[P][P2]){
new ModelProperty2<T, P, P2>(name, value);
}
}
}
const carModelCreator = ModelProperty2.for<Car>();
let engine2 = carModelCreator(['detials', 'good'],'22');
let engine2 = carModelCreator(['detials', 'good'],'Boy');
或者,您可以创建一个单一的重载函数,返回一个实例ModelProperty
,其中唯一的类型参数是最后一个属性的值,路径为string[]。在创建实例时获得类型安全性,但在此之后信息将丢失。
export class ModelProperty<T, V> {
constructor(public name: string[], public value: V) { }
static for<T>() {
function helper<P extends keyof T, P2 extends keyof T[P]>(name: [P, P2], value: T[P][P2])
function helper<P extends keyof T>(name: [P], value: T[P])
function helper(name: string[], value: any){
return new ModelProperty<T, any>(name, value);
}
return helper;
}
}
const carModelCreator = ModelProperty.for<Car>();
let engine1 = carModelCreator(['engine'], 22);
let engine2 = carModelCreator(['detials', 'good'],'Boy');