I have an interface called MyInterface that looks like this:
interface MyInterface<T, K extends keyof T> {
key: K
data: Array<T>
}
I want to constrain the key prop to be only keys that are present in T and also where the keys in T are only strings. The above interface constrains the key, but not its value to only strings. How can I add this constraint? Some examples of the behavior I'm looking for:
interface Data {
foo: string
bar: number
}
const d: Data[] = [{ foo: 'xxx', bar: 1 }]
// this is valid as the key is in the Data interface and the value of the key is a string
const a: MyInterface<Data, 'foo'> = { key: 'foo', data: d }
// this should be a type error as the value of bar is a number, not a string
const b: MyInterface<Data, 'bar'> = { key: 'bar', data: d }
// this should also be a type error as the key is not in the object
const c: MyInterface<Data, 'baz'> = { key: 'baz', data: d }
You would like to ensure that in MyInterface<T, K>, the T type has a string property at key K. There are a few ways to write this. For example, you could constrain K to KeysMatching<T, string> where KeysMatching is described in the answer to In TypeScript, how to get the keys of an object type whose values are of a given type?.
But it's even more straightforward to constrain T to Record<K, string> (using the Record<K, V> utility type):
interface MyInterface<T extends Record<K, string>, K extends keyof T> {
key: K
data: Array<T>
}
Then your examples work as desired:
const a: MyInterface<Data, 'foo'> = { key: 'foo', data: d }; // okay
const b: MyInterface<Data, 'bar'> = { key: 'bar', data: d }; // error!
// ----------------> ~~~~
// Type 'Data' does not satisfy the constraint 'Record<"bar", string>'.
// Types of property 'bar' are incompatible.
const c: MyInterface<Data, 'baz'> = { key: 'baz', data: d }; // error!
// ----------------> ~~~~
// Type 'Data' does not satisfy the constraint 'Record<"baz", string>'.
Playground link to code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With