如何强制数组条目成为 TypeScript 记录中的键?

How to enforce array entries to be keys in a record in TypeScript?

我想像这样定义一个 TypeScript 接口:

interface ObjectSchema {
  properties: Record<string, any>;
  required: Array<string>;
}

但增加了 required 的条目应该是 properties 的键的约束。我该怎么做?

一个有效类型的对象应该是:

let schemaA = {
  properties: {
    foo: {},
    bar: {},
  },
  required: ["foo"]
}

无效类型的对象将是:

let schemaA = {
  properties: {
    foo: {},
    bar: {},
  },
  required: ["baz"] // "baz" isn't a key in properties.
}

必须使用两种类型变量,一种用于 properties 的键,一种用于 required 的所述键的子集。

asObjectSchema只是一个利用推理的方便函数,所以我们不必注释类型变量。

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"'
})

Playground