我在Lovefield中有很多表,以及它们各自的接口,说明它们有哪些列。

例子:

export interface IMyTable {
  id: number;
  title: string;
  createdAt: Date;
  isDeleted: boolean;
}

我想有这个接口的属性名在这样的数组中:

const IMyTable = ["id", "title", "createdAt", "isDeleted"];

我不能直接基于接口IMyTable创建一个对象/数组,因为我将动态地获得表的接口名称。因此,我需要在接口中迭代这些属性,并从中获得一个数组。

我如何实现这个结果?


当前回答

有些人建议这样做,这是最简单的解决方案:

const properties: (keyof IMyTable)[] = ["id", "title", "createdAt", "isDeleted"];

然而,尽管这增加了一些类型安全性(我们不能错误地使用不存在的属性),但这并不是一个完全安全的解决方案,因为我们可能会错过一些属性并拥有重复的属性。所以我已经修复了这个问题,这个详细的解决方案是完全类型安全的,并防止了数组的编译时类型和运行时值之间的不一致:

const properties: [
    keyof Pick<IMyTable, 'id'>,
    keyof Pick<IMyTable, 'title'>,
    keyof Pick<IMyTable, 'createdAt'>,
    keyof Pick<IMyTable, 'isDeleted'>
] = ['id', 'title', 'createdAt', 'isDeleted'];

当然,这只适用于如果你不避免重复,但至少你只需要确保你正确地写所有属性一次(在Pick类型util),如果有任何错误,其余的将总是引发一个错误。我认为这是最健壮的解决方案中简单,容易理解和易读的解决方案。

其他回答

下面需要你自己列出键,但至少TypeScript会强制IUserProfile和IUserProfileKeys拥有完全相同的键(Required<T>是在TypeScript 2.8中添加的):

export interface IUserProfile  {
  id: string;
  name: string;
};
type KeysEnum<T> = { [P in keyof Required<T>]: true };
const IUserProfileKeys: KeysEnum<IUserProfile> = {
  id: true,
  name: true,
};

问题是类型在运行时不可用。我最终定义了一个对象,并从该对象派生了类型。您仍然可以获得类型支持,并获得从单个位置获得所有键的列表的能力。

const myTable =  {
  id: 0,
  title: '',
  createdAt: null as Date,
  isDeleted: false,
};

export type TableType = typeof myTable;
export type TableTypeKeys = (keyof TableType)[];
export const tableKeys: TableTypeKeys = Object.keys(
  myTable
) as TableTypeKeys;

由上面产生的隐式类型将是(你可以用VSCode或其他高质量IDE检查):

type TableType = {
    id: number;
    title: string;
    createdAt: Date;
    isDeleted: boolean;
}

type TableTypeKeys = ("id" | "title" | "createdAt" | "isDeleted")[]

在运行时,你将能够访问tableKeys数组

console.log(tableKeys);
// output: ["id" , "title" , "createdAt" , "isDeleted"]

这应该可以

var IMyTable: Array<keyof IMyTable> = ["id", "title", "createdAt", "isDeleted"];

or

var IMyTable: (keyof IMyTable)[] = ["id", "title", "createdAt", "isDeleted"];

这是一个艰难的问题!谢谢大家的帮助。

我的需要是将接口的键作为字符串数组来简化mocha/chai脚本。不关心在应用程序中使用(还),所以不需要创建ts文件。感谢ford04的帮助,他上面的解决方案是一个巨大的帮助,它的工作完美,没有编译器黑客。下面是修改后的代码:

选项2:基于TS编译器API的代码生成器(TS -morph)

节点模块

npm install --save-dev ts-morph

keys.ts

注意:这里假设所有ts文件都位于./src的根目录下,并且没有子文件夹,请相应地调整

import {
  Project,
  VariableDeclarationKind,
  InterfaceDeclaration,
} from "ts-morph";

// initName is name of the interface file below the root, ./src is considered the root
const Keys = (intName: string): string[] => {
  const project = new Project();
  const sourceFile = project.addSourceFileAtPath(`./src/${intName}.ts`);
  const node = sourceFile.getInterface(intName)!;
  const allKeys = node.getProperties().map((p) => p.getName());

  return allKeys;
};

export default Keys;

使用

import keys from "./keys";

const myKeys = keys("MyInterface") //ts file name without extension

console.log(myKeys)

也许太晚了,但是在TypeScript的2.1版本中,你可以使用keyof来获得这样的类型:

interface Person {
    name: string;
    age: number;
    location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string

来源:https://www.typescriptlang.org/docs/handbook/release notes/typescript - 2 - 1. - html # keyof-and-lookup-types