TypeScript'te nesneyi arabirime yayınla


94

Kodumda ekspres bir isteğin gövdesinden (gövde ayrıştırıcı ara yazılım kullanarak) bir arayüze bir döküm yapmaya çalışıyorum, ancak bu tür güvenliğini zorlamıyor.

Bu benim arayüzüm:

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

Bu, oyuncu kadrosunu 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 hizmet yöntemi:

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

Arayüz tanımıyla eşleşmeye yaklaşmayanlar da dahil olmak üzere her türlü argümanı iletebilirim ve bu kod iyi çalışacaktır. Yanıt gövdesinden arayüze dönüştürme mümkün değilse, Java veya C # gibi çalışma zamanında bir istisna atılmasını beklerdim.

TypeScript çevriminde sadece Type Assertion'ın olmadığını okudum, bu yüzden derleyiciye sadece bir nesnenin tipte olduğunu söyleyecektir x, yani ... Yanlış mıyım? Tip güvenliğini sağlamanın ve sağlamanın doğru yolu nedir?


1
Lütfen "çalışmıyor" olarak tanımlayın. Kesin ol. Bir hata mı var Hangisi? Derleme zamanında mı? İşlem esnasında? Ne oluyor?
JB Nizet

1
Çalışma zamanında kod, geçtiğim her nesne ile normal olarak yürütülür.
Elias Garcia

Ne sorduğunuz belli değil
Nitzan Tomer

Sorum, gelen nesnenin yazılı bir nesneye nasıl dönüştürüleceği. Oyuncu kadrosu mümkün değilse, çalışma zamanında Java, C # gibi bir istisna atın ...
Elias Garcia

Yanıtlar:


133

JavaScript'te döküm yoktur, bu nedenle "döküm başarısız olursa" atamazsınız.
Typecript , çevirmeyi destekler, ancak bu yalnızca derleme süresi içindir ve bunu şu şekilde yapabilirsiniz:

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

Değerin geçerli olup olmadığını çalışma zamanında kontrol edebilir ve bir hata oluşturmazsanız, 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

@Huyz'un da belirttiği gibi, tür ifadesine gerek yok çünkü isToDoDtobir tür koruma, yani bu yeterli olmalı:

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

this.toDoService.addToDo(req.body);

const toDo = req.body as IToDoDto;TS derleyicisinin IToDoDtobu noktada bir olduğunu bildiği için oyuncu kadrosuna ihtiyacınız olduğunu sanmıyorum
huyz

9
genel olarak tür iddiası arayanlar için <> kullanmayın. bu kullanımdan kaldırılmıştır. kullanımas
Abhishek Deb

" Javascript'te çevrim yok, bu yüzden" çevrim başarısız olursa " atamazsınız . " Daha da önemlisi, TypeScript'teki arayüzlerin eyleme geçirilemeyeceğini düşünüyorum; aslında% 100 sözdizimsel şekerdir . Yapıları kavramsal olarak korumayı kolaylaştırırlar , ancak aktarılan kod üzerinde gerçek bir etkisi yoktur - ki bu, OP'nin soru kanıtı olarak delicesine kafa karıştırıcı / anti-modeldir. Arayüzlerle eşleşmeyen şeylerin kopyalanmış JavaScript'e atılmaması için hiçbir neden yoktur; TypeScript tarafından bilinçli (ve zayıf, imo) bir seçimdir.
ruffin

@ruffin arayüzleri sözdizimsel şeker değildir, ancak onu yalnızca çalışma zamanında tutmak için bilinçli bir seçim yaptılar. bence bu harika bir seçim, bu şekilde çalışma zamanında performans kesintisi olmaz.
Nitzan Tomer

Tomayto tomahto ? Daktilo arayüzlerinden tip emniyet senin transpiled koduna uzatmak ve hatta tip emniyet edilir önceden çalışma zamanı değil ciddi sınırlı - biz OP'ın sayısında gördüğümüz gibi hiçbir tip emniyet hiç orada olduğu . TS, "Hey, bekle, senin anyolman garanti değil IToDoDto!" Diyebilirdi, ama TS bunu yapmamayı seçti. Derleyici yalnızca bazı tür çatışmalarını yakalarsa ve aktarılan kodda hiçbiri yoksa (ve haklıysanız, orijinalde daha net olmalıydım), arabirimler maalesef imo, [çoğunlukla?] Şekerdir.
ruffin

7

Uyumsuz türler ve TS derleyicisinin normalde şikayet ettiği arayüzler arasında bile bir tür dökümünü zorlamanın başka bir yolu:

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

  // ... do runtime checks here

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

Daha sonra bunu, belirli bir türe atılan nesneleri zorlamak için kullanabilirsiniz:

import { forceCast } from './forceCast';

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

Karmaşıklığı azaltmak adına yayınlamadan önce çalışma zamanı kontrolleri yapmanız gereken kısmı dışarıda bıraktığımı unutmayın. Projemde yaptığım şey, tüm .d.tsarayüz dosyalarımı JSON şemalarına derlemek ve ajvçalışma zamanında doğrulamak için kullanmaktır .


1

Herhangi birine yardımcı oluyorsa, bir nesneyi benzer bir arayüze sahip başka bir tür olarak ele almak istediğim bir sorun yaşıyordum. Aşağıdakileri denedim:

Linting geçmedi

const x = new Obj(a as b);

Linter, aüzerinde var olan özelliklerin eksik olduğundan şikayet ediyordu b. Başka bir deyişle, abazı özelliklere ve yöntemlere sahipti b, ama hepsi yoktu. Bu sorunu çözmek için VS Code'un önerisini takip ettim:

Linting ve testten geçti

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

Kodunuz, tipte buygulanmayan türdeki özelliklerden birini çağırmaya çalışırsa a, bir çalışma zamanı hatası gerçekleştirmeniz gerektiğini unutmayın.


1
Bu yanıtı bulduğuma sevindim, ancak ağ üzerinden veya başka bir uygulamaya 'x' gönderiyorsanız, kişisel bilgilerinizi sızdırıyor olabilirsiniz (örneğin 'a' bir kullanıcı ise), çünkü 'x' hala 'a' nın tüm özelliklerine sahiptir, sadece typcript için kullanılamaz.
Zoltán Matók

@ ZoltánMatók iyi bir nokta. Ayrıca, serileştirilmiş nesnenin ağ üzerinden gönderilmesiyle ilgili olarak , JavaScript ve yöntemler üzerinde Java stili alıcılar ve ayarlayıcılar için bir argüman vardır . getset
Jason
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.