TypeScript泛型keyof等概念困惑及ModelProperty类赋值报错疑问
let valueWhyError: V = t[this.name]; throw an error in this TypeScript generic class? Hey there! Let's unpack why that error is popping up in your ModelProperty class. It all comes down to how TypeScript handles generic parameters and type inference for class properties.
The Root Causes
Vis an independent generic parameter (not strictly tied toT[P])
Your class setsV = T[P]as a default type, butVremains a separate generic parameter. This means someone could explicitly pass a type forVthat's narrower thanT[P]. For example:// Here V is explicitly set to 22, not just the broader `number` type const engineProp = new ModelProperty<Car, 'engine', 22>('engine', 22);In this scenario,
t[this.name]resolves to typenumber(sinceCar['engine']isnumber), but you're trying to assign it to a variable of type22—which TypeScript correctly rejects, because not all numbers are equal to 22.TypeScript can't guarantee
T[P]matchesVin the method
Even if you never explicitly overrideV, TypeScript's type system doesn't assume thatVwill always equalT[P]inside thefunmethod. SinceVis a standalone generic parameter, it could be modified in a subclass or other instantiations whereVdiverges fromT[P]. TypeScript prioritizes type safety here, so it throws an error instead of making an unsafe assumption.
Fixes to Resolve the Error
Remove the
Vgeneric parameter entirely
If you don't need to narrowVbeyond the type ofT[P], just useT[P]directly for thevalueproperty. This eliminates the type mismatch entirely:export class ModelProperty<T, P extends keyof T> { constructor(public name: P, public value: T[P]) { } fun(t: T){ let valueWhyFixed: T[P] = t[this.name]; // No error! } }Add a constraint to tie
VtoT[P]
If you do need to keepV(for cases where you want a more specific type), add a constraintV extends T[P]and use a type assertion if you're confident the assignment is safe:export class ModelProperty<T, P extends keyof T, V extends T[P]> { constructor(public name: P, public value: V) { } fun(t: T){ let valueWhyFixed: V = t[this.name] as V; // Type assertion resolves the error } }Note: Type assertions bypass TypeScript's type checking, so only use this if you're certain
t[this.name]will always be compatible withVin your specific use cases.
内容的提问来源于stack exchange,提问作者amitdigga

