Tìm kiếm trang web

typescript - làm thế nào để tránh lỗi biên dịch cho các thuộc tính enumerable: false


Tôi đang cố gắng học TS và tôi gặp phải một tình huống kỳ lạ.

Tôi có một đối tượng với một thuộc tính được đặt là không liệt kê:

let person = {
  name: 'Harry'
}

Object.defineProperty(person,'salary',{enumerable: false, value : 15});

console.log(person.salary); // 15

Điều này hoạt động khi chạy chương trình, tuy nhiên, trình biên dịch sẽ báo lỗi:

Thuộc tính 'salary' không tồn tại trên kiểu '{ name: string; }'

điều này là điều được mong đợi.

Tôi có thể bỏ qua cài đặt này bằng cách đặt loại người là bất kỳ, nhưng điều đó không giống như một giải pháp gọn gàng.

Có cách nào khác để làm điều đó không? Toán tử khẳng định không null không hoạt động cho việc này.

Tôi sẽ rất trân trọng nếu ai đó có thể chia sẻ một số kiến thức về điều này.

Câu trả lời #1

Mặc dù bạn có thể thay đổi chú thích kiểu cho person, có thể như sau:

let person: { name: string; salary?: number } = {
  name: 'Harry'
};

hoặc thậm chí:

let person = {
  name: 'Harry'
} as { name: string; salary: number };

Phương pháp an toàn nhất có lẽ là (lạm dụng) các hàm khẳng định trong phiên bản 3.7:

function defineProperty<
    O,
    Property extends PropertyKey,
    Value
>(o: O, key: Property, attributes: PropertyDescriptor & ThisType<any> & { value: Value }): asserts o is O & Record<Property, Value> {
    Object.defineProperty(o, key, attributes);
}

Về cơ bản, đây là một hàm bao bọc cho Object.defineProperty mà nói với TypeScript, nếu hàm này không ném ra lỗi, thì kiểu của giá trị được cho o là O & Record<Property, Value>.

Vậy khi bạn sử dụng nó, bạn sẽ nhận được một loại như thế này:

defineProperty(person,'salary',{enumerable: false, value : 15});

person
// ^? { name: string; } & Record<"salary", number>

Sân chơi


Và nếu bạn thực sự muốn, bạn cũng có thể làm cho kiểu kết quả trở nên sạch sẽ hơn bằng cách thay đổi phép khẳng định thành như sau:

asserts o is (O & Record<Property, Value> extends infer T extends O ? { [K in keyof T]: T[K] } : O)

Như bạn có thể thấy ở đây khi di chuột qua person, kiểu bây giờ là { name: string; salary: number; } thay vì một phép giao thừa xấu xí.