我正在尝试想出一种方法来使用 TypeORM 获得更好的类型安全性。以下是一些示例 TypeORM 实体定义。
import { BaseEntity, Entity, Column, ManyToMany, JoinTable, ManyToOne, OneToMany } from 'typeorm';
@Entity()
class Product extends BaseEntity {
@Column({ type: 'text' })
public name: string;
@Column({ type: 'text' })
public description: string;
@ManyToMany(_ => Category, category => category.products)
@JoinTable()
public categories: Category[];
}
@Entity()
class Category extends BaseEntity {
@Column({ type: 'text' })
public name: string;
@ManyToMany(_ => Product, product => product.categories)
public products: Product[];
@ManyToOne(_ => Supplier, supplier => supplier.categories, { nullable: false })
public supplier: Supplier;
}
@Entity()
class Supplier extends BaseEntity {
@Column('text')
public name: string;
@Column({ type: 'boolean', default: true })
public isActive: boolean;
@OneToMany(_ => Category, category => category.supplier)
public categories: Category[];
}
我正在尝试定义一种类型,该类型仅对作为实体本身的实体的属性有效。最好用一个例子来解释:
type Relations<T extends BaseEntity> = {
// An object whose:
// - Keys are some (or all) of the keys in type T, whose type is something which extends BaseEntity.
// - Values are another Relations object for that key.
}
// Some examples
// Type error: "color" is not a property of Product.
const a: Relations<Product> = {
color: {}
}
// Type error: "name" property of Product is not something that extends "BaseEntity".
const a: Relations<Product> = {
name: {}
}
// OK
const a: Relations<Product> = {
categories: {}
}
// Type error: number is not assignable to Relations<Category>
const a: Relations<Product> = {
categories: 42
}
// Type error: "description" is not a property of Category.
const a: Relations<Product> = {
categories: {
description: {}
}
}
// Type error: "name" property of Category is not something that extends "BaseEntity".
const a: Relations<Product> = {
categories: {
name: {}
}
}
// OK
const a: Relations<Product> = {
categories: {
supplier: {}
}
}
// Type error: Date is not assignable to Relations<Supplier>
const a: Relations<Product> = {
categories: {
supplier: new Date()
}
}
// etc.
到目前为止,我想出了以下内容,但它不起作用,甚至可能还没有接近正确的答案:
type Flatten<T> = T extends Array<infer I> ? I : T;
type ExcludeNonEntity<T> = T extends BaseEntity | Array<BaseEntity> ? Flatten<T> : never;
type Relations<T extends BaseEntity> = {
[P in keyof T as ExcludeNonEntity<P>]: Relations<T[P]>;
};