我正在try 定义对象的类型化array.共享相同泛型类型 struct 的对象和泛型类型接受类型参数以提供更具体的(约束对象的其他(数组)属性的允许值).
Example
类型化数组应强制其元素遵守如下规则:
{ tableName: 'roles', ...}
应将returnColumns
限制为只有'id' and/or 'name'
,并且
{ tableName: 'permissions', ...}
应该将returnColumns
限制为只有'id' and/or 'permission'
例如:
[
{
tableName: 'roles',
returnColumns: ['id', 'name'] // should be OK
},
{
tableName: 'roles',
returnColumns: ['name'] // should be OK
},
{
tableName: 'permissions',
returnColumns: ['id', 'permission'] // should be OK
},
{
tableName: 'permissions',
returnColumns: ['id'] // should be OK
},
{
tableName: 'roles',
returnColumns: ['id', 'permission'] // should not be OK, permission belongs to permissions
},
]
Breakdown
第1部分:工作类型化对象
在下面的示例中,单个对象的类型正确:
type JoinTable<T> = {
tableName: T;
returnColumns: TableColumns<TypeOfTableName<T>>[];
};
const rolesExample1: JoinTable<'roles'> = {
tableName: 'roles',
returnColumns: ['id', 'name'] // OK, because roles is only allowed id and/or name
};
const rolesExample2: JoinTable<'roles'> = {
tableName: 'roles',
returnColumns: ['id', 'permission'] // Should fail, because roles is only allowed id and name, and permission is not available to roles
};
const permsExample3: JoinTable<'permissions'> = {
tableName: 'permissions',
returnColumns: ['id', 'permission'] // OK, because permissions is only allowed id and/or permission
};
const permsExample4: JoinTable<'permissions'> = {
tableName: 'permissions',
returnColumns: ['id', 'name'] // Should fail, because permissions is only allowed id and/or permission, and name is not available to permissions
};
第2部分:失败的类型化对象数组
在下面的示例中,我们看到了失败:
type JoinTable<T> = {
tableName: T;
returnColumns: TableColumns<TypeOfTableName<T>>[];
};
type JoinColumns<T> = T extends unknown
? TableColumns<TypeOfTableName<T>>
: never;
// This code allows for returnColumns elements to be any value of any table
export type Joins<T extends TableName> = {
joins: (Omit<JoinTable<RelatedTableName<T>>, 'returnColumns'> & {
returnColumns: JoinColumns<RelatedTableName<T>>[]
})[]
};
const combinedJoins: Joins<'role_permissions'> = {
joins: [
{
tableName: 'roles',
returnColumns: ['id', 'name', 'permission'] // Should (but doesn't) fail, because permission is not available to roles
},
{
tableName: 'permissions',
returnColumns: ['id', 'name', 'permission'] // Should (but doesn't) fail, because name is not available to permissions
},
{
tableName: 'roles',
returnColumns: ['id', 'name', 'uh-oh'] // Should fail (and does) because nothing supports uh-oh
},
{
tableName: 'roles',
returnColumns: ['id', 'name'] // should be OK
},
{
tableName: 'roles',
returnColumns: ['name'] // should be OK
},
{
tableName: 'permissions',
returnColumns: ['id', 'permission'] // should be OK
},
]
};
第3部分:从哪里开始
我最初使用的是以下Joins类型的变体:
export type Joins<T extends TableName> = {
joins: JoinTable<RelatedTableName<T>>[]
};
当数组中只有一种对象类型时,这是有效的,但对于两种对象类型,突然之间,redouColumns的值被限制为仅限于数组中所有对象共享的那些值.
例如: if there was both an roles and a permissions object in the array, the values of returnColumns could only be id which both types have in common.
数据模式和支持类型:数据库、表名、表列、表关系等
export interface Database {
golf_scores: {
Tables: {
permissions: {
Row: {
id: number;
permission: string;
};
Relationships: [];
};
role_permissions: {
Row: {
id_permissions: number;
id_roles: number;
};
Relationships: [
{
referencedRelation: 'permissions';
referencedColumns: ['id'];
},
{
referencedRelation: 'roles';
referencedColumns: ['id'];
}
];
};
roles: {
Row: {
id: number;
name: string;
};
Relationships: [];
};
};
}
}
export type TableName = keyof Database['golf_scores']['Tables'];
export type TableColumns<T extends TableName> =
keyof Database['golf_scores']['Tables'][T]['Row'];
export type TypeOfTableName<T> = T extends TableName ? T : never;
type TablesRelationships<T extends TableName> =
Database['golf_scores']['Tables'][T]['Relationships'];
export type RelatedTableName<T extends TableName> =
TablesRelationships<T>[number]['referencedRelation'];
(注:此处的工作示例:(typescriptlang.org)
Final comments
到目前为止,似乎只可能拥有所有表中的所有值,或者只拥有所有表中通用的所有表中的值.我一直在探索一些类似的解决方案:Typescript, merge object types?个,但我开始怀疑我正在try 的是否可能?