Search code examples
typescriptgenericskeyof

Make a generic type Array<keyof T> require all keys of T


I would like to declare a type that requires all the keys of a given type T to be included in an array, e.g.:

checkKeys<T>(arr: Array<keyof T>): void {
  // do something
}

interface MyType {
  id: string;
  value: number;
}

Currently if a call checkKeys<MyType>, TS will consider the value passed as valid if it contains any key of MyType (id | value):

checkKeys<MyType>(['id', 'value']); // valid

checkKeys<MyType>(['id']); // valid

checkKeys<MyType>(['id', 'values']); // invalid

Is it possible to require that all keys are specified in the array?


Solution

  • You can't do that with an array type (at least I am not aware of a way to spread the union of keys into a tuple type, there may be one I'm just not aware of it). An alternative would be to use an object literal to achieve a similar effect. The syntax is a bit more verbose but the compiler will validate that only the correct keys are specified. We will use the Record mapped type and we can use the 0 literal types for values as only the keys matter.

    function checkKeys<T>(o: Record<keyof T, 0>): void {
         // do something
    }
    
    interface MyType {
        id: string;
        value: number;
    }
    
    checkKeys<MyType>({ id: 0, value: 0 }); // valid
    
    checkKeys<MyType>({ id: 0 }); // invalid
    
    checkKeys<MyType>({ id: 0, values: 0 }); // invalid