Làm cách nào để tạo một đối tượng dựa trên định nghĩa tệp giao diện trong TypeScript?


313

Tôi đã định nghĩa một giao diện như thế này:

interface IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
 }

Tôi định nghĩa một biến như thế này:

var modal: IModal;

Tuy nhiên, khi tôi cố gắng thiết lập thuộc tính của phương thức, nó cho tôi một thông báo nói rằng

"cannot set property content of undefined"

Có thể sử dụng một giao diện để mô tả đối tượng phương thức của tôi không và nếu có thì tôi nên tạo nó như thế nào?

Câu trả lời:


426

Nếu bạn đang tạo biến "phương thức" ở nơi khác và muốn nói với TypeScript thì tất cả sẽ được thực hiện, bạn sẽ sử dụng:

declare const modal: IModal;

Nếu bạn muốn tạo một biến thực sự sẽ là một thể hiện của IModal trong TypeScript, bạn sẽ cần xác định đầy đủ.

const modal: IModal = {
    content: '',
    form: '',
    href: '',
    $form: null,
    $message: null,
    $modal: null,
    $submits: null
};

Hoặc nói dối, với xác nhận loại, nhưng bạn sẽ mất an toàn loại vì bây giờ bạn sẽ không xác định được ở những nơi không mong muốn và có thể là lỗi thời gian chạy, khi truy cập modal.content, v.v. (các thuộc tính mà hợp đồng nói sẽ ở đó).

const modal = {} as IModal;

Lớp mẫu

class Modal implements IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
}

const modal = new Modal();

Bạn có thể nghĩ "hey đó thực sự là một bản sao của giao diện" - và bạn đã đúng. Nếu lớp Modal là triển khai duy nhất của giao diện IModal, bạn có thể muốn xóa hoàn toàn giao diện và sử dụng ...

const modal: Modal = new Modal();

Thay vì

const modal: IModal = new Modal();

2
Cảm ơn. Tôi đã hy vọng thoát khỏi việc phải xác định tất cả các nội dung phương thức ban đầu. Sẽ dễ dàng hơn nếu thay vì một giao diện tôi đã xác định Modal là một lớp có các thuộc tính và sau đó sử dụng new và constructor để thiết lập tất cả các giá trị ban đầu?

1
Có - bạn có thể định nghĩa một lớp và sau đó bạn sẽ chỉ phải tạo các thể hiện mới khi bạn cần chúng. Bạn có cần một ví dụ?
Fenton

2
Tôi đã thêm một ví dụ và một lưu ý về giao diện.
Fenton

21
var modal = <IModal>{};đây là những gì tôi đang tìm kiếm ;-) cảm ơn!
Huyền thoại

5
FYI, tốt hơn là sử dụng {} as IModalhơn là <IModal>{}. Nó loại bỏ sự mơ hồ trong ngữ pháp ngôn ngữ khi sử dụng các <foo>xác nhận kiểu trong JSX. Đọc thêm . Và tất nhiên, sử dụng lethoặc constthay vì var.
Alex Klaus

191

Nếu bạn muốn một đối tượng trống của giao diện, bạn có thể thực hiện chỉ:

var modal = <IModal>{};

Ưu điểm của việc sử dụng các giao diện thay cho các lớp để cấu trúc dữ liệu là nếu bạn không có bất kỳ phương thức nào trên lớp, nó sẽ hiển thị trong JS được biên dịch dưới dạng một phương thức trống. Thí dụ:

class TestClass {
    a: number;
    b: string;
    c: boolean;
}

biên dịch thành

var TestClass = (function () {
    function TestClass() {
    }
    return TestClass;
})();

mà không mang giá trị. Mặt khác, các giao diện, hoàn toàn không hiển thị trong JS mà vẫn cung cấp các lợi ích của cấu trúc dữ liệu và kiểm tra kiểu.


1
`Để thêm vào nhận xét trên. Để gọi một hàm "updateModal (IModal modalInstance) {}", bạn có thể tạo một phiên bản nội tuyến của giao diện 'IModal', như thế này: // một số mã ở đây, nơi có thể truy cập hàm updateModal & IModal: <IModal> {// dòng này tạo ra một nội dung thể hiện: '', biểu mẫu: '', href: '', $ form: null, $ message: null, $ modal: null, $ submitits: null}); // hoàn thành mã của bạn `
Nắng

bằng cách sử dụng var modal= <abc>{}chúng ta vừa gán phương thức abc của đối tượng rỗng nhưng chúng ta đã khai báo kiểu phương thức ở đâu? tôi đang sử dụng typecript6.
Pardeep Jain 7/1/2016

Điều này không làm việc cho tôi, tôi đã phải khởi tạo toàn bộ đối tượng như đã nêu trong câu trả lời được chấp nhận.
Rahul Sonwanshi


22

Tôi nghĩ rằng về cơ bản bạn có năm lựa chọn khác nhau để làm như vậy. Lựa chọn trong số họ có thể dễ dàng tùy thuộc vào mục tiêu bạn muốn đạt được.

Cách tốt nhất trong hầu hết các trường hợp để sử dụng một lớp và khởi tạo nó , bởi vì bạn đang sử dụng TypeScript để áp dụng kiểm tra kiểu.

interface IModal {
    content: string;
    form: string;
    //...

    //Extra
    foo: (bar: string): void;
}

class Modal implements IModal {
    content: string;
    form: string;

    foo(param: string): void {
    }
}

Ngay cả khi các phương pháp khác đang cung cấp các cách dễ dàng hơn để tạo một đối tượng từ một giao diện, bạn nên xem xét tách giao diện của mình ra, nếu bạn đang sử dụng đối tượng của mình cho các vấn đề khác nhau và nó không gây ra sự phân tách quá mức về giao diện:

interface IBehaviour {
    //Extra
    foo(param: string): void;
}

interface IModal extends IBehaviour{
    content: string;
    form: string;
    //...
}

Mặt khác, ví dụ trong quá trình kiểm tra đơn vị mã của bạn (nếu bạn không thể áp dụng phân tách mối quan tâm thường xuyên), bạn có thể chấp nhận những hạn chế vì lợi ích của năng suất. Bạn có thể áp dụng các phương pháp khác để tạo giả chủ yếu cho các giao diện * .d.ts của bên thứ ba lớn. Và nó có thể là một nỗi đau khi luôn luôn thực hiện đầy đủ các đối tượng ẩn danh cho mọi giao diện lớn.

Trên đường dẫn này, tùy chọn đầu tiên của bạn là tạo một đối tượng trống :

 var modal = <IModal>{};

Thứ hai để nhận ra đầy đủ các phần bắt buộc trong giao diện của bạn . Nó có thể hữu ích cho dù bạn đang gọi các thư viện JavaScript của bên thứ 3, nhưng tôi nghĩ bạn nên tạo một lớp thay thế, như trước đây:

var modal: IModal = {
    content: '',
    form: '',
    //...

    foo: (param: string): void => {
    }
};

Thứ ba, bạn có thể tạo chỉ một phần của giao diện của mình và tạo một đối tượng ẩn danh , nhưng theo cách này, bạn có trách nhiệm thực hiện hợp đồng

var modal: IModal = <any>{
    foo: (param: string): void => {

    }
};

Tóm tắt câu trả lời của tôi ngay cả khi các giao diện là tùy chọn, vì chúng không được dịch mã JavaScript, TypeScript có sẵn để cung cấp một mức độ trừu tượng mới, nếu được sử dụng một cách khôn ngoan và nhất quán. Tôi nghĩ, chỉ vì bạn có thể loại bỏ chúng trong hầu hết các trường hợp từ mã của riêng bạn mà bạn không nên.



12

Vì tôi không tìm thấy câu trả lời bằng nhau ở đầu và câu trả lời của tôi là khác nhau. Tôi làm:

modal: IModal = <IModal>{}

2

Sử dụng giao diện của bạn, bạn có thể làm

class Modal() {
  constructor(public iModal: IModal) {
   //You now have access to all your interface variables using this.iModal object,
   //you don't need to define the properties at all, constructor does it for you.
  }
}

2

Đây là một cách tiếp cận khác:

Bạn có thể chỉ cần tạo một đối tượng thân thiện với ngôn ngữ như thế này

const modal: IModal = {} as IModal;

Hoặc một phiên bản mặc định dựa trên giao diện và với các mặc định hợp lý, nếu có

const defaultModal: IModal = {
    content: "",
    form: "",
    href: "",
    $form: {} as JQuery,
    $message: {} as JQuery,
    $modal: {} as JQuery,
    $submits: {} as JQuery
};

Sau đó, các biến thể của thể hiện mặc định chỉ đơn giản bằng cách ghi đè một số thuộc tính

const confirmationModal: IModal = {
    ...defaultModal,     // all properties/values from defaultModal
    form: "confirmForm"  // override form only
}

1

Nhiều giải pháp cho đến nay đã đăng các xác nhận loại sử dụng và do đó không ném các lỗi biên dịch nếu các thuộc tính giao diện được yêu cầu bị bỏ qua trong quá trình thực hiện.

Đối với những người quan tâm đến một số giải pháp mạnh mẽ, nhỏ gọn khác :

Tùy chọn 1: Khởi tạo một lớp ẩn danh thực hiện giao diện:

new class implements MyInterface {
  nameFirst = 'John';
  nameFamily = 'Smith';
}();

Tùy chọn 2: Tạo chức năng tiện ích:

export function impl<I>(i: I) { return i; }

impl<MyInterface>({
  nameFirst: 'John';
  nameFamily: 'Smith';
})

0

Bạn có thể đặt giá trị mặc định bằng cách sử dụng Class.

Không có Trình xây dựng lớp:

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
};

class Modal implements IModal {
  content = "";
  form = "";
  href: string;  // will not be added to object
  isPopup = true;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}

Với lớp xây dựng

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
}

class Modal implements IModal {
  constructor() {
    this.content = "";
    this.form = "";
    this.isPopup = true;
  }

  content: string;

  form: string;

  href: string; // not part of constructor so will not be added to object

  isPopup: boolean;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.