2015-11-25 16 views
8

Tôi đang tạo bản đồ đơn giản giữa cấu trúc dữ liệu frontend/backend. Để làm được điều mà tôi đã tạo ra một trang trí trông giống như sau:Chỉ định thuộc tính cho nguyên mẫu không có kiểu trang trí

function ApiField(
    apiKey: string, 
    setFn: (any) => any = (ret) => ret, 
    getFn: (any) => any = (ret) => ret 
) { 
    return function (target: AbstractModel, propertyKey: string) { 
     target.apiFieldsBag = target.apiFieldsBag || {}; 
     _.assign(
      target.apiFieldsBag, 
      { 
       [propertyKey]: { 
        apiKey: apiKey, 
        setFn: setFn, 
        getFn: getFn 
       } 
      } 
     ); 
    }; 
} 

Và đây là cách tôi sử dụng nó:

class AbstractCar { 
    @ApiField('id') 
    public id: string = undefined; 
} 

class BMW extends AbstractCar { 
    @ApiField('cylinders') 
    public cylinderCount: number; 
} 

class VW extends AbstractCar { 
    @ApiField('yearCompanyFounded') 
    public yearEstablished: number; 
} 

Vấn đề mà tôi nhìn thấy là thay vì đối tượng thực tế được truyền tới trang trí luôn là nguyên mẫu của nó:

__decorate([ 
    ApiField('yearCompanyFounded') 
], VW.prototype, "yearEstablished", void 0); 

Điều đó có nghĩa là khi tôi gán công cụ cho cá thể trong trang trí, nó luôn gắn liền với nguyên mẫu lần lượt có nghĩa là các thuộc tính mà tôi muốn được xác định chỉ có cá thể VW cũng có sẵn trên AbstractCar và lớp BMW (trong ví dụ này là yearEstablished). Điều này làm cho nó không thể có hai thuộc tính có cùng tên nhưng các trường API khác nhau trong hai lớp khác nhau.

Có cách nào để phá vỡ hành vi này không?

+0

ECMAScript 7 ... !!!! – Arjun

+0

Ngoài ra, bạn không cần 'target.apiFieldsBag =' trước '_.assign ('. Bạn cũng có tùy chọn để sử dụng ES6 'Object.assign()' thay vì '_.assign() ' –

+0

Vâng tôi nghĩ rằng khi tôi nhìn lại câu hỏi một lần nữa. Cảm ơn cho người đứng đầu anyway :) –

Trả lời

4

Ngay bây giờ, tất cả ba lớp học được thêm thuộc tính để cùng một đối tượng. Chìa khóa để sửa lỗi này là để sao chép đối tượng trên target.data để mỗi lớp đang sử dụng một đối tượng khác thay vì tất cả chúng đều đề cập đến cùng một đối tượng.

Dưới đây là một ví dụ đơn giản thể hiện một cách để làm điều này:

function ApiField(str: string) { 
    return function (target: any, propertyKey: string) { 
     // I tested with Object.assign, but it should work with _.assign the same way 
     target.data = _.assign({}, target.data, { 
      [propertyKey]: str 
     }); 
    }; 
} 

class AbstractCar { 
    @ApiField("car") 
    public carID; 
} 

class BMW extends AbstractCar { 
    @ApiField("bmw") 
    public bmwID; 
} 

class VW extends AbstractCar { 
    @ApiField("vw") 
    public vwID; 
} 

AbstractCar.prototype.data; // Object {carID: "car"} 
BMW.prototype.data;   // Object {carID: "car", bmwID: "bmw"} 
VW.prototype.data;   // Object {carID: "car", vwID: "vw"} 
+0

Điều này, tôi muốn BMW Class để kế thừa các dữ liệu từ AbstractCar –

+0

@justNik ah, ok. Tôi cập nhật câu trả lời của tôi với một cái gì đó mà làm việc cho điều đó. –

+0

Ngọt ngào, cảm ơn! Hài hước như thế nào một điều phức tạp tìm kiếm nhọt xuống đến một vấn đề javascript phổ biến. Nói về việc mất tích rừng cho cây –

4

Vấn đề là public bên trong một lớp không phải là JavaScript chuẩn, nó chỉ là thứ mà TypeScript thực hiện. Vì vậy, bạn phải cẩn thận, bởi vì bất cứ điều gì bạn làm có thể phá vỡ trong tương lai.

Một khả năng là sử dụng Object.assign() thêm các thuộc tính dụ (IINM, apiFieldsBag nên được chuyển từ các đối tượng được tạo ra bởi các đối tượng theo nghĩa đen để this):

class AbstractCar { 
    constructor() { 
     Object.assign(this, { 
      @ApiField('id') 
      id: undefined, 
     }); 
    } 
} 
+0

Tôi đang thực sự sử dụng typescript, do đó, sử dụng' public' nên được tốt :) Nhưng tôi sẽ cung cấp cho giải pháp của bạn một thử –

+1

@justNik Tôi biết rằng 'public' là TypeScript. Vấn đề với 'public foo = x' là nó không tồn tại như một thực thể thực tế (ví dụ: một thuộc tính), nó được biên dịch thành một nhiệm vụ trong hàm tạo. Do đó, không rõ phải trang trí gì, bởi vì, ATM, chỉ có các lớp học và tài sản mới có thể được trang trí. –

+0

@justNik Tôi chỉ nhìn vào mã mà một trang web 'công khai' được biên dịch và TypeScript thực sự trang trí một thuộc tính của nguyên mẫu. Đó là một lỗi, IMO (nó nên trang trí một tài sản của 'this' trong constructor) - bạn có thể muốn gửi một báo cáo lỗi. –

Các vấn đề liên quan