I want to define a TypeScript interface like this:
interface ObjectSchema {
properties: Record<string, any>;
required: Array<string>;
}
but with the added constraint that entries of required
should be keys of properties
. How do I go about this?
A validly typed object would be:
let schemaA = {
properties: {
foo: {},
bar: {},
},
required: ["foo"]
}
A invalidly typed object would be:
let schemaA = {
properties: {
foo: {},
bar: {},
},
required: ["baz"] // "baz" isn't a key in properties.
}
Two type variables must be used, one for the keys of properties
, one for the subset of said keys for required
.
asObjectSchema
is just a convenient function to exploit the inference, so we don't have to annotate the type variables.
interface ObjectSchema<A extends string, B extends A> {
properties: Record<A, any>
required: Array<B>
}
const asObjectSchema = <A extends string, B extends A>(
schema: ObjectSchema<A, B>
): ObjectSchema<A, B> => schema
const schemaA = asObjectSchema({
properties: {
foo: {},
bar: {},
},
required: ['foo'],
})
const schemaB = asObjectSchema({
properties: {
foo: {},
bar: {},
},
required: ['baz'], // Type '"baz"' is not assignable to type '"foo" | "bar"'
})