TypeScript'te nesneyi arayüze dönüştür
Express'te (body-parser ara katmanını kullanarak) bir isteğin gövdesinden bir arabirime kodumda dönüştürme yapmaya çalışıyorum, ancak bu tür güvenliğini zorlamıyor.
Bu benim arayüzüm:
export interface IToDoDto {
description: string;
status: boolean;
};
İşte dönüşümü yapmaya çalıştığım kod:
@Post()
addToDo(@Response() res, @Request() req) {
const toDo: IToDoDto = <IToDoDto> req.body; // <<< cast here
this.toDoService.addToDo(toDo);
return res.status(HttpStatus.CREATED).end();
}
Ve son olarak, çağrılan servis metodu:
public addToDo(toDo: IToDoDto): void {
toDo.id = this.idCounter;
this.todos.push(toDo);
this.idCounter++;
}
Herhangi bir argümanı geçirebilirim, arayüz tanımıyla hemen hemen hiç eşleşmeyenler de dahil, ve bu kod sorunsuz çalışacaktır. Eğer yanıt gövdesinden arayüze dönüşüm mümkün değilse, Java veya C#'ta olduğu gibi çalışma zamanında bir istisna fırlatılmasını beklerdim.
TypeScript'te casting olmadığını, sadece Type Assertion olduğunu okudum, bu yüzden bu sadece derleyiciye bir nesnenin x türünde olduğunu söyleyecek, yani... Yanılıyor muyum? Tür güvenliğini zorlamak ve sağlamak için doğru yol nedir?
Cevap #1
Javascript'te tip dönüştürme (casting) yoktur, bu yüzden "dönüştürme başarısız olursa" fırlatamazsınız.
Typescript tip dönüştürmeyi destekler ancak bu yalnızca derleme zamanı içindir ve bunu şu şekilde yapabilirsiniz:
const toDo = req.body as IToDoDto;
// or
const toDo = <IToDoDto> req.body; // deprecated
Değerin geçerli olup olmadığını çalışma zamanında kontrol edebilir ve geçerli değilse hata fırlatabilirsiniz, yani:
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();
}
Düzenle
Dediği gibi @huyz, isToDoDto bir tür koruyucu olduğu için tür dönüşümüne gerek yok, bu nedenle bu yeterli olmalı:
if (!isToDoDto(req.body)) {
throw new Error("invalid request");
}
this.toDoService.addToDo(req.body);
Cevap #2
TS derleyicisinin genellikle hata verdiği uyumsuz türler ve arayüzler arasında bile bir tür dönüşümünü zorlamanın başka bir yolu işte burada:
export function forceCast<T>(input: any): T {
// ... do runtime checks here
// @ts-ignore <-- forces TS compiler to compile this as-is
return input;
}
Sonra bunu, nesneleri belirli bir türe zorla dönüştürmek için kullanabilirsin:
import { forceCast } from './forceCast';
const randomObject: any = {};
const typedObject = forceCast<IToDoDto>(randomObject);
Karmaşıklığı azaltmak için dönüştürmeden önce çalıştırma zamanı kontrolleri yapmanız gereken kısmı çıkardığımı unutmayın. Projemde yaptığım şey, tüm .d.ts arayüz dosyalarımı JSON şemalarına derlemek ve ajv kullanarak çalıştırma zamanında doğrulamak.
Cevap #3
Eğer birine yardımcı olursa, ben, benzer bir arayüze sahip başka bir tür gibi bir nesneyi ele almak istediğim bir sorun yaşıyordum. Şunu denedim:
Lint kontrolünden geçmedi
const x = new Obj(a as b);
Linter, a'nın b'de bulunan özelliklerden eksik olduğunu belirtiyordu. Başka bir deyişle, a, b'nin bazı özelliklerine ve yöntemlerine sahipti, ama hepsine değil. Bunu aşmak için, VS Code'un önerisini takip ettim:
Lint kontrolünden ve testlerden geçti
const x = new Obj(a as unknown as b);
Kodunuz, tür a'da uygulanmamış olan tür b'de var olan özelliklerden birini çağırmaya çalışırsa, bir çalışma zamanı hatası alacağınızı unutmayın.
