I am wondering if it is possible in TS to enforce the type of the properties for a generic. I would like to only allow passing a generic of an object type with 'string' properties. Raise an error if for instance the passed generic interface would contain number or symbols properties.
Here is a POC of what I tried and commented the behaviour I am looking for:
class Test<T extends {[key: string]: any}>{
private data: T;
public getValue<K extends keyof T>(key: K): T[K] {
return this.data[key];
}
}
// the property is a string = ok
const okay = new Test<{ "aString": string }>();
// the property is a number = should raise an error
const shouldFail = new Test<{ 0: string }>();
If the object has a string index we can index the object by number as well, so there is no reason for the compiler to throw an error number keys. This is by design.
declare let skeys: { [key: string]: number }
let v1 = skeys[0] // number
let v2 = skeys["0"] // number
declare let nkeys: { [key: number]: number }
let v3 = nkeys[0] // number
let v4 = nkeys["0"] // error
declare let snkeys: {
[key: number]: number;
[key: string]: string | number // The string index has to contain any value reuned by the number index
}
let v5 = snkeys[0] // number
let v6 = snkeys["0"] // string| number
We can use a conditional type to force an error if the object contains any non-string keys. The error will not be very pretty, but it is readable and can get the job done:
class Test<T extends { [key: string]: any } & (keyof T extends string ? {} : "T must obnly have string keys") >{
private data!: T;
public getValue<K extends keyof T>(key: K): T[K] {
return this.data[key];
}
}
// the property is a string = ok
const okay = new Test<{ "aString": string }>();
// Error: Type '{ 0: string; }' does not satisfy the constraint '{ [key: string]: any; } & "T must only have string keys"'.
const shouldFail = new Test<{ 0: string }>();
Note
If you don't have any other constraints on the values of T
a simple object
type would work as well
class Test<T extends object & (keyof T extends string ? {} : "T must only have string keys") >{ }
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.