There isn't a specific type that directly fits your requirements. However, you can represent it as a generic type. Here's an example:
export interface SomeCustomInterface<K extends PropertyKey, R extends K> {
testProperty: Record<K, {
prop1: string;
prop2?: string;
prop3?: string;
}>;
requiredProperties: R[]
}
This approach will restrict things the way you intend, but when creating a value of the SomeCustomInterface
type, you must specify the K
and R
parameters. To have the compiler infer these, you can use a helper function:
const asCustomInterface = <K extends PropertyKey, R extends K>(x: SomeCustomInterface<K, R>) => x;
Usage example:
const customValue = asCustomInterface({
testProperty: {
apple: {
prop1: 'example',
},
banana: {
prop1: 'some text',
},
mango: {
prop1: 'content',
},
},
requiredProperties: ["apple", "banana"]
});
You'll encounter an error if you add an element to requiredProperties
that is not a key in testProperty
:
asCustomInterface({
testProperty: { x: { prop1: "" }, y: { prop1: "" }, z: { prop1: "" } },
requiredProperties: ["x", "y", "z", "w"] // error!
})
Making SomeCustomInterface<K, R>
a generic type introduces complexity, as any values or functions dealing with them need to carry additional type parameters. You may want to reserve generics for scenarios where input from external users is uncertain, while using a non-generic version internally for easier handling:
// Code visible to external users, enforcing constraints
function publicFunction<K extends string, R extends K>(
someCustomInterface: SomeCustomInterface<K, R>
) {
internalFunction(someCustomInterface)
}
// Internal code, working with non-generic version
type SimplifiedCustomInterface = SomeCustomInterface<string, string>
const simplifiedValue: SimplifiedCustomInterface = customValue; // accepted
function internalFunction(simplifiedCustomInterface: SimplifiedCustomInterface) {
// Perform operations
}
Click here to view the Playground link