Truyền đối tượng tới giao diện trong TypeScript


95

Tôi đang cố gắng truyền mã của mình từ phần thân của một yêu cầu ở dạng express (sử dụng phần mềm trung gian phân tích cú pháp cơ thể) sang một giao diện, nhưng nó không thực thi an toàn kiểu.

Đây là giao diện của tôi:

export interface IToDoDto {
  description: string;
  status: boolean;
};

Đây là mã mà tôi đang cố gắng truyền:

@Post()
addToDo(@Response() res, @Request() req) {
  const toDo: IToDoDto = <IToDoDto> req.body; // <<< cast here
  this.toDoService.addToDo(toDo);
  return res.status(HttpStatus.CREATED).end();
}

Và cuối cùng, phương thức dịch vụ đang được gọi:

public addToDo(toDo: IToDoDto): void {
  toDo.id = this.idCounter;
  this.todos.push(toDo);
  this.idCounter++;
}

Tôi có thể chuyển bất kỳ đối số nào, ngay cả những đối số không khớp với định nghĩa giao diện và mã này sẽ hoạt động tốt. Tôi mong đợi, nếu quá trình truyền từ cơ thể phản hồi đến giao diện không thể thực hiện được, thì một ngoại lệ sẽ được đưa ra trong thời gian chạy như Java hoặc C #.

Tôi đã đọc rằng trong truyền TypeScript không tồn tại, chỉ có Type Assertion, vì vậy nó sẽ chỉ cho trình biên dịch biết rằng một đối tượng thuộc loại x, vì vậy ... Tôi có nhầm không? Cách phù hợp để thực thi và đảm bảo an toàn kiểu là gì?


1
Hãy xác định "nó không hoạt động". Chính xác. Có lỗi không? Cái nào? Tại thời điểm biên dịch? Trong thời gian chạy? Điều gì xảy ra?
JB Nizet

1
Trong thời gian chạy, mã thực thi bình thường, với bất kỳ đối tượng nào tôi chuyển.
Elias Garcia

Không rõ bạn đang hỏi gì
Nitzan Tomer

Câu hỏi của tôi là làm thế nào để truyền đối tượng đến thành một đối tượng được định kiểu. Nếu các diễn viên là không thể, ném một ngoại lệ khi chạy, như Java, C # ...
Elias Garcia

Điều này có trả lời câu hỏi của bạn không?
Truyền kiểu TypeScript

Câu trả lời:


136

Không có truyền trong javascript, vì vậy bạn không thể ném nếu "truyền không thành công".
Typecript hỗ trợ truyền nhưng đó chỉ là thời gian biên dịch và bạn có thể làm như thế này:

const toDo = <IToDoDto> req.body;
// or
const toDo = req.body as IToDoDto;

Bạn có thể kiểm tra trong thời gian chạy xem giá trị có hợp lệ không và nếu không gặp lỗi, tức là:

function isToDoDto(obj: any): obj is IToDoDto {
    return typeof obj.description === "string" && typeof obj.status === "boolean";
}

@Post()
addToDo(@Response() res, @Request() req) {
    if (!isToDoDto(req.body)) {
        throw new Error("invalid request");
    }

    const toDo = req.body as IToDoDto;
    this.toDoService.addToDo(toDo);
    return res.status(HttpStatus.CREATED).end();
}

Biên tập

Như @huyz đã chỉ ra, không cần xác nhận kiểu vì isToDoDtolà kiểu bảo vệ, vì vậy điều này là đủ:

if (!isToDoDto(req.body)) {
    throw new Error("invalid request");
}

this.toDoService.addToDo(req.body);

Tôi không nghĩ rằng bạn cần các diễn viên trong const toDo = req.body as IToDoDto;kể từ khi biên dịch TS biết rằng nó là một IToDoDtovào thời điểm này
huyz

9
đối với bất kỳ ai đang tìm kiếm xác nhận kiểu nói chung, không sử dụng <>. cái này không được dùng nữa. sử dụngas
Abhishek Deb

" Không có truyền trong javascript, vì vậy bạn không thể ném nếu" truyền không thành công ". " Tôi nghĩ, hơn nữa, các giao diện trong TypeScript không thể xử lý được; trên thực tế, chúng là đường tổng hợp 100% . Chúng làm cho việc duy trì cấu trúc về mặt khái niệm trở nên dễ dàng hơn , nhưng không có tác động thực tế nào đến mã được chuyển đổi - tức là imo, cực kỳ khó hiểu / phản mẫu, như câu hỏi của OP. Không có lý do gì những thứ không khớp với giao diện không thể chuyển JavaScript vào; đó là một lựa chọn có ý thức (và kém, imo) của TypeScript.
ruffin

Giao diện @ruffin không phải là đường cú pháp, nhưng họ đã thực hiện một lựa chọn có ý thức để chỉ giữ nó trong thời gian chạy. tôi nghĩ đó là một lựa chọn tuyệt vời, theo cách đó không có hình phạt về hiệu suất trong thời gian chạy.
Nitzan Tomer

Tomayto tomahto ? An toàn kiểu từ các giao diện trong TypeScript không mở rộng đến mã được chuyển của bạn, và thậm chí trước thời gian chạy, an toàn kiểu bị hạn chế nghiêm trọng - như chúng ta thấy trong vấn đề của OP, nơi không có an toàn kiểu nào cả . TS có thể nói: "Này, khoan đã, của bạn anyvẫn chưa được đảm bảo IToDoDto!", Nhưng TS đã chọn không. Nếu trình biên dịch chỉ bắt được một số xung đột kiểu và không có trong mã đã chuyển đổi (và bạn nói đúng; tôi nên nói rõ hơn @ điều đó trong bản gốc), thật không may, giao diện là imo, [hầu hết là?] Đường.
ruffin

7

Đây là một cách khác để ép kiểu truyền ngay cả giữa các kiểu và giao diện không tương thích mà trình biên dịch TS thường phàn nàn:

export function forceCast<T>(input: any): T {

  // ... do runtime checks here

  // @ts-ignore <-- forces TS compiler to compile this as-is
  return input;
}

Sau đó, bạn có thể sử dụng nó để buộc các đối tượng đúc thành một loại nhất định:

import { forceCast } from './forceCast';

const randomObject: any = {};
const typedObject = forceCast<IToDoDto>(randomObject);

Lưu ý rằng tôi đã bỏ qua phần bạn phải kiểm tra thời gian chạy trước khi truyền vì lợi ích giảm độ phức tạp. Những gì tôi làm trong dự án của mình là biên dịch tất cả .d.tscác tệp giao diện của tôi thành các lược đồ JSON và sử dụng ajvđể xác thực trong thời gian chạy.


1

Nếu nó giúp ích cho bất kỳ ai, tôi đang gặp sự cố khi tôi muốn coi một đối tượng là một loại khác có giao diện tương tự. Tôi đã cố gắng như sau:

Không vượt qua linting

const x = new Obj(a as b);

Người cho thuê đã phàn nàn rằng ađã thiếu các tài sản tồn tại trên đó b. Nói cách khác, acó một số thuộc tính và phương thức b, nhưng không phải tất cả. Để giải quyết vấn đề này, tôi đã làm theo đề xuất của VS Code:

Đã vượt qua bài kiểm tra và in linting

const x = new Obj(a as unknown as b);

Lưu ý rằng nếu mã của bạn cố gắng gọi một trong các thuộc tính tồn tại trên loại bmà không được triển khai trên loại a, bạn sẽ nhận ra lỗi thời gian chạy.


1
Tôi rất vui vì tôi đã tìm thấy câu trả lời này, nhưng lưu ý rằng nếu bạn đang gửi 'x' qua mạng hoặc đến một ứng dụng khác, bạn có thể bị rò rỉ thông tin cá nhân (nếu 'a' là người dùng chẳng hạn), vì 'x' vẫn có tất cả các thuộc tính của 'a', chúng chỉ không có sẵn cho bản đánh chữ.
Zoltán Matók

@ ZoltánMatók điểm tốt. Ngoài ra, liên quan đến việc gửi đối tượng được tuần tự hóa qua mạng, có một đối số cho trình nhận và thiết lập kiểu Java trên JavaScript getsetcác phương thức.
Jason
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.