我在Lovefield中有很多表,以及它们各自的接口,说明它们有哪些列。
例子:
export interface IMyTable {
id: number;
title: string;
createdAt: Date;
isDeleted: boolean;
}
我想有这个接口的属性名在这样的数组中:
const IMyTable = ["id", "title", "createdAt", "isDeleted"];
我不能直接基于接口IMyTable创建一个对象/数组,因为我将动态地获得表的接口名称。因此,我需要在接口中迭代这些属性,并从中获得一个数组。
我如何实现这个结果?
正如其他人已经说过的,这些类型在运行时不可用,因此您需要生成它们或手工编写它们。
如果您手动编写它们,那么简单的Array<keyof IMyTable>不会验证缺少的键。
这里有一个非常棒的答案,它回答了使用类型安全声明键数组的问题。(功劳归于他。)相关代码:
export interface IMyTable {
id: number;
title: string;
createdAt: Date;
isDeleted: boolean;
}
type Invalid<T> = ['Needs to be all of', T];
const arrayOfAll =
<T>() =>
<U extends T[]>(
...array: U & ([T] extends [U[number]] ? unknown : Invalid<T>[])
) =>
array;
const fields = arrayOfAll<keyof IMyTable>()(
'id',
'createdAt',
'title',
'isDeleted',
);
如果缺少字段,则会显示错误。
有些人建议这样做,这是最简单的解决方案:
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),如果有任何错误,其余的将总是引发一个错误。我认为这是最健壮的解决方案中简单,容易理解和易读的解决方案。