如何在TypeScript中为TypeORM模型实现类似Laravel的通用fill()方法?
fill() 方法用于TypeORM模型 Got it, let's tackle replicating Laravel's handy fill() method for TypeORM models in TypeScript—no manual field assignments required for every model!
核心思路
Laravel's fill() uses a $fillable whitelist to filter out unwanted fields. We can replicate this in TypeScript using either a base class (simple and straightforward) or a class decorator (more flexible, no forced inheritance). Both approaches automatically handle filtering extra fields.
方法一:创建通用填充基类
This is the easiest approach—create an abstract base class that all your TypeORM models inherit from. The base class will implement the fill() logic by reading the model's own properties and only assigning those present in the input data.
import { BaseEntity } from "typeorm"; export abstract class FillableBaseEntity extends BaseEntity { fill<T extends FillableBaseEntity>(data: Partial<T>): this { // Get all own property names of the current model (excludes BaseEntity props) const allowedFields = Object.getOwnPropertyNames(this); // Only assign values for fields that exist on the model allowedFields.forEach(field => { if (data.hasOwnProperty(field)) { // @ts-ignore Skip type check since we confirm the field belongs to the model this[field] = data[field]; } }); return this; } }
Use it with your Requisition model
import { Entity, Column } from "typeorm"; import { FillableBaseEntity } from "./FillableBaseEntity"; @Entity() export class Requisition extends FillableBaseEntity { @Column() title!: string; @Column() reference!: string; }
How to call it
Just like Laravel's fill()—extra fields get automatically ignored:
const rawApiData = { title: "New Office Equipment Request", reference: "REQ-2024-001", extraField: "this gets ignored", anotherUnwantedField: "so does this" }; const requisition = new Requisition().fill(rawApiData); // Only title and reference are assigned to the model
方法二:使用类装饰器(更灵活)
If you don't want all models to inherit the same base class, use a decorator to add the fill() method. This also supports a custom fillable whitelist—exactly like Laravel's $fillable array.
First, create the decorator:
import { BaseEntity } from "typeorm"; type Constructor<T = BaseEntity> = new (...args: any[]) => T; export function Fillable(fillable?: string[]) { return function <T extends Constructor>(target: T) { return class extends target { fill(data: Record<string, any>): this { // Use custom fillable list if provided, else use model's own properties const allowedFields = fillable || Object.getOwnPropertyNames(this); allowedFields.forEach(field => { if (data[field] !== undefined) { // @ts-ignore Skip type check for simplicity this[field] = data[field]; } }); return this; } }; }; }
Use the decorator with your model
Two usage options:
- Auto-detect model properties (same as base class approach):
import { Entity, Column } from "typeorm"; import { Fillable } from "./FillableDecorator"; @Entity() @Fillable() // No args = use all model properties export class Requisition extends BaseEntity { @Column() title!: string; @Column() reference!: string; }
- Custom fillable whitelist (explicitly define allowed fields):
@Entity() @Fillable(['title', 'reference']) // Only these fields can be filled export class Requisition extends BaseEntity { @Column() title!: string; @Column() reference!: string; @Column({ default: false }) isApproved!: boolean; // This field will be ignored by fill() }
How to call it
Same as before—extra fields get filtered out:
const rawData = { title: "Printer Replacement", reference: "REQ-2024-002", isApproved: true, extraJunk: "ignored" }; const requisition = new Requisition().fill(rawData); // isApproved remains false (its default value) since it's not in fillable
注意事项
- For TypeORM models,
Object.getOwnPropertyNamesreliably fetches all fields decorated with@Column, so the auto-detect approach works well for most cases. - If your model has properties you don't want to be fillable (like relationships or computed fields), use the custom
fillablewhitelist to avoid accidental assignments. - The
@ts-ignoreis used for simplicity—if you want stricter type safety, you can add generic type constraints, but it's rarely necessary for this use case.
内容的提问来源于stack exchange,提问作者Edwin

