Typescript: allow a generic type to only be an object with 'string' properties

前端 未结 1 1681
心在旅途
心在旅途 2021-01-18 02:08

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\' pr

相关标签:
1条回答
  • 2021-01-18 02:55

    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") >{ }
    
    0 讨论(0)
提交回复
热议问题