Câu hỏi Làm thế nào để tạo một đối tượng mới từ tham số kiểu trong lớp chung trong bản ghi?


Tôi đang cố gắng tạo một đối tượng mới của một tham số kiểu trong lớp chung của tôi. Trong lớp "View" của tôi, tôi có 2 danh sách các đối tượng kiểu generic được truyền vào như là các tham số kiểu, nhưng khi tôi cố gắng thực hiện new TGridView() typescript nói Could not find symbol 'TGridView'...

Đây là mã:

module AppFW {
    // Represents a view
    export class View<TFormView extends FormView, TGridView extends GridView> {
        // The list of forms 
        public Forms: { [idForm: string]: TFormView; } = {};

        // The list of grids
        public Grids: { [idForm: string]: TGridView; } = {};

        public AddForm(formElement: HTMLFormElement, dataModel: any, submitFunction?: (e: SubmitFormViewEvent) => boolean): FormView {
            var newForm: TFormView = new TFormView(formElement, dataModel, submitFunction);
            this.Forms[formElement.id] = newForm;
            return newForm;
        }

        public AddGrid(element: HTMLDivElement, gridOptions: any): GridView {
            var newGrid: TGridView = new TGridView(element, gridOptions);
            this.Grids[element.id] = newGrid;
            return newGrid;
        }
    }
}

Tôi có thể tạo các đối tượng từ một loại chung chung không?


76
2018-06-29 16:10


gốc




Các câu trả lời:


Vì JavaScript được biên dịch có tất cả thông tin loại đã bị xóa, bạn không thể sử dụng T để tạo một đối tượng mới.

Bạn có thể làm điều này theo cách không chung chung bằng cách chuyển kiểu vào hàm tạo.

class TestOne {
    hi() {
        alert('Hi');
    }
}

class TestTwo {
    constructor(private testType) {

    }
    getNew() {
        return new this.testType();
    }
}

var test = new TestTwo(TestOne);

var example = test.getNew();
example.hi();

Bạn có thể mở rộng ví dụ này bằng cách sử dụng Generics để thắt chặt các loại:

class TestBase {
    hi() {
        alert('Hi from base');
    }
}

class TestSub extends TestBase {
    hi() {
        alert('Hi from sub');
    }
}

class TestTwo<T extends TestBase> {
    constructor(private testType: new () => T) {
    }

    getNew() : T {
        return new this.testType();
    }
}

//var test = new TestTwo<TestBase>(TestBase);
var test = new TestTwo<TestSub>(TestSub);

var example = test.getNew();
example.hi();

51
2018-06-29 19:16



Đây là siêu sạch sẽ và hoạt động tuyệt vời! - Jaume Mussons Abad


Để tạo một đối tượng mới trong mã chung, bạn cần tham chiếu đến kiểu bằng hàm tạo của nó. Vì vậy, thay vì viết điều này:

function activatorNotWorking<T extends IActivatable>(type: T): T {
    return new T(); // compile error could not find symbol T
}

Bạn cần phải viết điều này:

function activator<T extends IActivatable>(type: { new(): T ;} ): T {
    return new type();
}

var classA: ClassA = activator(ClassA);

Xem câu hỏi này: Loại suy luận chung với đối số lớp


87
2017-11-02 05:52



Hơi trễ (nhưng hữu ích) bình luận - nếu constructor của bạn lấy args thì new() cũng cần phải - hoặc chung chung hơn: type: {new(...args : any[]): T ;} - Rycochet
Những gì là IActivatable? Tôi không thể tìm thấy nó trong bất kỳ tài liệu nào. - Yoda
@Yoda IActivatable là một giao diện tự tạo, xem câu hỏi khác: stackoverflow.com/questions/24677592/… - Jamie


Tất cả các thông tin kiểu được xóa ở phía JavaScript và do đó bạn không thể tạo mới T giống như trạng thái @Sohnee, nhưng tôi muốn có tham số đã nhập được truyền vào hàm tạo:

class A {
}

class B<T> {
    Prop: T;
    constructor(TCreator: { new (): T; }) {
        this.Prop = new TCreator();
    }
}

var test = new B<A>(A);

15
2018-01-18 13:39





export abstract class formBase<T> extends baseClass {

  protected item = {} as T;
}

Đối tượng của nó sẽ có thể nhận bất kỳ tham số nào, tuy nhiên, kiểu T chỉ là một tham chiếu kiểu và không thể được tạo thông qua một hàm tạo. Nghĩa là, nó sẽ không tạo ra bất kỳ đối tượng phụ lớp nào.


7
2018-01-16 11:53



Xin vui lòng đọc Cách trả lời và giải thích mã này làm gì. - CodeCaster
Cẩn thận, điều này có thể hoạt động nhưng đối tượng kết quả sẽ không thuộc Loại T, vì vậy mọi getters / setters được định nghĩa trong T có thể không hoạt động. - Daniel Ormeño
@ DanielOrmeño chăm sóc để giải thích? Ý bạn là như thế nào? Mã của tôi dường như đang hoạt động bằng đoạn mã này. Cảm ơn. - eestein
Javascript là một ngôn ngữ thông dịch và ecmascript chưa có tham chiếu đến các kiểu hoặc các lớp. Vì vậy, T chỉ là một tham chiếu cho bản ghi. - jalescardoso


tôi sử dụng điều này: let instance = <T>{}; nó thường hoạt động CHỈNH SỬA 1:

export class EntityCollection<T extends { id: number }>{
  mutable: EditableEntity<T>[] = [];
  immutable: T[] = [];
  edit(index: number) {
    this.mutable[index].entity = Object.assign(<T>{}, this.immutable[index]);
  }
}

0
2017-10-03 15:07



Điều này sẽ không thực sự khởi tạo một phiên bản mới của T, nó sẽ chỉ tạo một đối tượng trống mà TypeScript nghĩ thuộc loại T. Bạn có thể muốn giải thích câu trả lời của bạn chi tiết hơn một chút. - Sandy Gifford
Tôi nói nó thường hoạt động. Nó chính xác như bạn nói. Trình biên dịch không rên rỉ và bạn có mã chung. Bạn có thể sử dụng cá thể này để tự thiết lập các thuộc tính mà bạn muốn mà không cần hàm khởi tạo rõ ràng. - Bojo


Tôi đã cố gắng để nhanh chóng chung chung từ bên trong một lớp cơ sở. Không có ví dụ nào ở trên làm việc cho tôi vì họ yêu cầu loại bê tông để gọi phương thức nhà máy.

Sau khi nghiên cứu một thời gian về điều này và không thể tìm thấy một giải pháp trực tuyến, tôi phát hiện ra rằng điều này dường như làm việc.

 protected activeRow: T = {} as T;

Các mảnh:

 activeRow: T = {} <-- activeRow now equals a new object...

...

 as T; <-- As the type I specified. 

Tất cả cùng nhau

 export abstract class GridRowEditDialogBase<T extends DataRow> extends DialogBase{ 
      protected activeRow: T = {} as T;
 }

0
2017-10-09 22:54