我有数据库表的以下架构列(用于西瓜数据库)。
const columns = [
  { name: "created_at", type: "number", isOptional: true },
  { name: "created_by", type: "string" },
  { name: "is_corrupt", type: "boolean", isOptional: true },
];
我想创建一个泛型,它将根据上面的示例创建以下类型,我该怎么做?
type ExpectedInferredTypeFromColumns = {
  created_at: number | null;
  created_by: string;
  is_corrupt: boolean | null;
};
我的尝试:
type InferTypeFromColumns<T extends ReadonlyArray<Column>> = {
  [K in T extends ReadonlyArray<infer U>
    ? U extends { name: string }
      ? U["name"]
      : never
    : never]: T extends ReadonlyArray<infer U>
    ? U extends { type: "number"; isOptional: true }
      ? number | null
      : U extends { type: "number" }
      ? number
      : U extends { type: "string"; isOptional: true }
      ? string | null
      : U extends { type: "string" }
      ? string
      : U extends { type: "boolean"; isOptional: true }
      ? boolean | null
      : U extends { type: "boolean" }
      ? boolean
      : never
    : never;
};
type MyInferredType = InferTypeFromColumns<typeof columns>;
// Produces: => 
// type MyInferredType = {
//     created_at: string | number | boolean | null;
//     created_by: string | number | boolean | null;
//     is_corrupt: string | number | boolean | null;
// }
正如你所看到的,我的尝试不太符合我的要求ExpectedInferredTypeFromColumns
就这样:游乐场
const columns = [
  { name: "created_at", type: "number", isOptional: true },
  { name: "created_by", type: "string" },
  { name: "is_corrupt", type: "boolean", isOptional: true },
] as const; // define as const so `columns[number]` gives precise type inference
type Column = {
  name: string;
  type: "number" | "string" | "boolean"
  isOptional?: boolean
}
type TypeMapper = {
  boolean: boolean;
  string: string;
  number: number;
}
// You need to create a union depending if `isOptional` is defined or not
type InferTypeFromColumns<T extends ReadonlyArray<Column>> = {
  [K in T[number] as K['name']]: TypeMapper[K['type']] | (K['isOptional'] extends true ? null : never)
}
type Test = InferTypeFromColumns<typeof columns>
/*
type Test = {
    created_at: number | null;
    created_by: string;
    is_corrupt: boolean | null;
}
*/
如果您需要拥有可选键,则需要将可选键和必需键进行交集,如下所示:
type RequiredInferTypeFromColumns<T extends ReadonlyArray<Column>> = {
  [K in T[number] as K['isOptional'] extends true ? never : K['name']]: TypeMapper[K['type']]
}
type OptionalInferTypeFromColumns<T extends ReadonlyArray<Column>> = {
  [K in T[number] as K['isOptional'] extends true ? K['name'] : never]?: TypeMapper[K['type']] | null
}
type Intersection<A, B> = A & B extends infer U
  ? { [P in keyof U]: U[P] }
  : never;
type Test = Intersection<RequiredInferTypeFromColumns<typeof columns>, OptionalInferTypeFromColumns<typeof columns>>
/*
type Test = {
    created_by: string;
    created_at?: number | null | undefined;
    is_corrupt?: boolean | null | undefined;
}
*/
这个答案的灵感来自于这个解决方案:Conditionally apply ? 每个属性的映射类型中的修饰符
| 归档时间: | 
 | 
| 查看次数: | 188 次 | 
| 最近记录: |