In TypeScript, there is no predefined type that functions in this specific manner. Rather, you must create a generic type with parameters corresponding to the literal types of the `promptField` and `valueField` properties. Here's an example:
type OptionsItem<KP extends string, KV extends string> =
{ [P in KP]: string } & { [P in KV]: SimpleValue }
interface Options<KP extends string, KV extends string> {
inline?: OptionsItem<KP & {}, KV & {}>[]
promptField?: KP;
selectedValues?: unknown[];
valueField?: KV;
}
The `OptionsItem<KP, KV>` type represents an intersection of two mapped types equivalent to `Record<KP, string>` and `Record<KV, SimpleValue>`. It ensures that each object has a `string` property at keys of type `KP` and a `SimpleValue` property at keys of type `KV`.
The `Options<KP, KV>` uses `KP` and `KV` appropriately and also assigns them to the `inline` property. I have excluded `| unknown[]` from the type as it can cause unexpected behavior by making all values `unknown`. Instead, use explicit types for clarity.
I've utilized `OptionsItem<KP & {}, KV & {}>` rather than just `OptionsItem<KP, KV>` to prevent inference issues when checking against `KP` and `KV` inferred from other properties.
If repeatedly specifying type arguments like in the sample object creation seems unnecessary, consider using a generic helper function for type argument inference:
const asOptions =
<KP extends string = "prompt", KV extends string = "value">(
o: Options<KP, KV>) => o;
You can now write `const o1 = asOptions({ ... })`, allowing the compiler to infer the type arguments automatically.
This setup provides default values for `KP` and `KV` if they cannot be inferred from the passed object, resulting in clearer code and error detection.
By utilizing such tools, you get both type safety and enhanced developer experience without sacrificing productivity.