没有简单的方法可以从接口创建键数组。类型在运行时被擦除,并且对象类型(无序,命名)在没有某种黑客手段的情况下无法转换为元组类型(有序,无命名)。
选项1:手动方式
// Record type ensures, we have no double or missing keys, values can be neglected
function createKeys(keyRecord: Record<keyof IMyTable, any>): (keyof IMyTable)[] {
return Object.keys(keyRecord) as any
}
const keys = createKeys({ isDeleted: 1, createdAt: 1, title: 1, id: 1 })
// const keys: ("id" | "title" | "createdAt" | "isDeleted")[]
(+)简单(-)数组返回类型,无元组(+-)带有自动完成功能的手动写入
扩展:我们可以尝试花哨并使用递归类型来生成元组。这对我来说仅适用于几个道具(〜5,6),直到性能大幅下降。TS也未正式支持深度嵌套的递归类型- 为了完整起见,在此列出此示例。
选项2:基于TS编译器API(ts-morph)的代码生成器
// ./src/mybuildstep.ts
import {Project, VariableDeclarationKind, InterfaceDeclaration } from "ts-morph";
const project = new Project();
// source file with IMyTable interface
const sourceFile = project.addSourceFileAtPath("./src/IMyTable.ts");
// target file to write the keys string array to
const destFile = project.createSourceFile("./src/generated/IMyTable-keys.ts", "", {
overwrite: true // overwrite if exists
});
function createKeys(node: InterfaceDeclaration) {
const allKeys = node.getProperties().map(p => p.getName());
destFile.addVariableStatement({
declarationKind: VariableDeclarationKind.Const,
declarations: [{
name: "keys",
initializer: writer =>
writer.write(`${JSON.stringify(allKeys)} as const`)
}]
});
}
createKeys(sourceFile.getInterface("IMyTable")!);
destFile.saveSync(); // flush all changes and write to disk
使用编译并运行此文件后tsc && node dist/mybuildstep.js
,将./src/generated/IMyTable-keys.ts
生成具有以下内容的文件:
// ./src/generated/IMyTable-keys.ts
const keys = ["id","title","createdAt","isDeleted"] as const;
(+)自动解决方案(+)确切的元组类型(-)需要构建步骤
PS:我选择了ts-morph
,因为它是原始TS编译器API的简单替代方案。