Jak zainicjować nową klasę w TS
taki sposób (przykład, C#
aby pokazać, czego chcę):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
[edytuj]
Kiedy pisałem to pytanie, byłem czystym programistą .NET bez dużej wiedzy o JS. Również TypeScript był czymś zupełnie nowym, ogłoszonym jako nowy nadzbiór JavaScript oparty na języku C #. Dziś widzę, jak głupie było to pytanie.
W każdym razie, jeśli ktoś nadal szuka odpowiedzi, zapoznaj się z możliwymi rozwiązaniami poniżej.
Pierwszą rzeczą do odnotowania jest to, że w TS nie powinniśmy tworzyć pustych klas dla modeli. Lepszym sposobem jest utworzenie interfejsu lub typu (w zależności od potrzeb). Dobry artykuł od Todda Motto: https://ultimatecourses.com/blog/classes-vs-interfaces-in-typescript
ROZWIĄZANIE 1:
type MyType = { prop1: string, prop2: string };
return <MyType> { prop1: '', prop2: '' };
ROZWIĄZANIE 2:
type MyType = { prop1: string, prop2: string };
return { prop1: '', prop2: '' } as MyType;
ROZWIĄZANIE 3 (kiedy naprawdę potrzebujesz zajęć):
class MyClass {
constructor(public data: { prop1: string, prop2: string }) {}
}
// ...
return new MyClass({ prop1: '', prop2: '' });
lub
class MyClass {
constructor(public prop1: string, public prop2: string) {}
}
// ...
return new MyClass('', '');
Oczywiście w obu przypadkach typy rzutowania mogą nie być potrzebne ręcznie, ponieważ zostaną one usunięte z typu zwracanego przez funkcję / metodę.
źródło
return new MyClass { Field1: "ASD", Field2: "QWE" };
Odpowiedzi:
Aktualizacja
Od czasu napisania tej odpowiedzi pojawiły się lepsze sposoby. Zobacz pozostałe odpowiedzi poniżej, które mają więcej głosów i lepszą odpowiedź. Nie mogę usunąć tej odpowiedzi, ponieważ jest ona oznaczona jako zaakceptowana.
Stara odpowiedź
W kodepleksie TypeScript występuje problem, który opisuje to: Obsługa inicjatorów obiektów .
Jak już wspomniano, można to zrobić już za pomocą interfejsów w TypeScript zamiast klas:
źródło
Person
, ale wcale nie jest to przypadekPerson
. Wyobraź sobie, żePerson
tak naprawdę byłaby to klasa ze złożonym konstruktorem i szeregiem metod, takie podejście upadłoby na pierwszy plan. To dobrze, że wiele osób uznało twoje podejście za przydatne, ale nie jest to rozwiązanie tego pytania, jak zostało powiedziane, i równie dobrze możesz użyć klasy Osoba w twoim przykładzie zamiast interfejsu, byłby to ten sam typ.Zaktualizowano 07.12.2016: Typescript 2.1 wprowadza mapowane typy i zapewnia
Partial<T>
, co pozwala to zrobić ....Oryginalna odpowiedź:
Moje podejście polega na zdefiniowaniu oddzielnej
fields
zmiennej przekazywanej do konstruktora. Sztuką jest ponowne zdefiniowanie wszystkich pól klasy dla tego inicjalizatora jako opcjonalnych. Kiedy obiekt jest tworzony (z ustawieniami domyślnymi), po prostu przypisujesz obiekt inicjalizującythis
;lub zrób to ręcznie (nieco bezpieczniej):
stosowanie:
i wyjście konsoli:
Daje to podstawową inicjalizację bezpieczeństwa i właściwości, ale wszystko jest opcjonalne i może być nieczynne. Zostaniesz pozostawiony domyślnym ustawieniom klasy, jeśli nie przejdziesz pola.
Możesz także mieszać go z wymaganymi parametrami konstruktora - trzymaj
fields
się końca.Myślę, że mniej więcej w stylu C #, jak zamierzacie ( faktyczna składnia inicjalizacji pola została odrzucona ). Wolałbym właściwy inicjator pola, ale nie wygląda na to, żeby to się jeszcze wydarzyło.
Dla porównania, jeśli zastosujesz metodę rzutowania, twój obiekt inicjalizujący musi mieć WSZYSTKIE pola dla typu, na który rzutujesz, oraz nie może uzyskać żadnych funkcji specyficznych dla klasy (lub pochodnych) utworzonych przez samą klasę.
źródło
Partial<>
, po prostuPerson
- to będzie wymagało przekazania obiektu, który ma wymagane pola. To powiedziawszy, zobacz tutaj pomysły (patrz Wybierz), które ograniczają mapowanie typów do niektórych pól.public constructor(init?:Partial<Person>) { Object.assign(this, init); }
Poniżej znajduje się rozwiązanie, które łączy krótszą aplikację w
Object.assign
celu dokładniejszego modelowania oryginalnegoC#
wzoru.Najpierw jednak przejrzyjmy oferowane dotychczas techniki, które obejmują:
Object.assign
Partial<T>
sztuczka w konstruktorze kopiowaniaObject.create
zamiastObject.assign
Oczywiście, każdy ma swoje zalety / wady. Modyfikacja klasy docelowej w celu utworzenia konstruktora kopii nie zawsze może być opcją. A „rzutowanie” traci wszelkie funkcje związane z typem celu.
Object.create
wydaje się mniej atrakcyjna, ponieważ wymaga dość szczegółowej mapy deskryptorów właściwości.Najkrótsza, ogólna odpowiedź
Oto kolejne podejście, które jest nieco prostsze, zachowuje definicję typu i powiązane prototypy funkcji oraz dokładniej modeluje zamierzony
C#
wzorzec:Otóż to. Jedynym dodatkiem do
C#
wzorca sąObject.assign
2 nawiasy i przecinek. Sprawdź działający przykład poniżej, aby potwierdzić, że zachowuje prototypy funkcji typu. Nie wymaga konstruktorów ani sprytnych sztuczek.Przykład roboczy
Ten przykład pokazuje, jak zainicjować obiekt za pomocą aproksymacji
C#
inicjalizatora pola:źródło
Możesz wpływać na anonimowy obiekt rzucony w typie swojej klasy. Bonus : W studiu wizualnym korzystasz w ten sposób z inteligencji :)
Edytować:
OSTRZEŻENIE Jeśli klasa ma metody, instancja klasy nie uzyska ich. Jeśli AClass ma konstruktor, nie zostanie on wykonany. Jeśli użyjesz instanceof AClass, otrzymasz fałsz.
Podsumowując, powinieneś używać interfejsu, a nie klasy . Najczęstszym zastosowaniem jest model domeny zadeklarowany jako Plain Old Objects. Rzeczywiście, w przypadku modelu domeny lepiej użyć interfejsu zamiast klasy. Interfejsy są używane w czasie kompilacji do sprawdzania typów i, w przeciwieństwie do klas, interfejsy są całkowicie usuwane podczas kompilacji.
źródło
AClass
zawarte metody,anInstance
nie dostaną ich.anInstance instanceof AClass
, otrzymaszfalse
w czasie wykonywania.Sugeruję podejście, które nie wymaga Typescript 2.1:
Kluczowe punkty:
Partial<T>
nie jest wymaganyźródło
new Person(<Person>{});
(ponieważ casting) i też jest jasne; używanie częściowe <T> obsługuje funkcje. Ostatecznie, jeśli masz wymagane pola (plus funkcje prototypowe), musisz zrobić:init: { name: string, address?: string, age: number }
i upuścić rzutowanie.class
następnievar
, jeśli to zrobięvar dog: {name: string} = {name: 'will be assigned later'};
, to kompiluje i działa. Jakikolwiek niedobór lub problem? Och,dog
ma bardzo mały zakres i jest specyficzny, co oznacza tylko jeden przypadek.Byłbym bardziej skłonny zrobić to w ten sposób, używając (opcjonalnie) automatycznych właściwości i wartości domyślnych. Nie zasugerowałeś, że dwa pola są częścią struktury danych, dlatego właśnie wybrałem tę metodę.
Możesz mieć właściwości w klasie, a następnie przypisać je w zwykły sposób. I oczywiście mogą być lub nie być wymagane, więc to także coś innego. Po prostu jest to taki miły cukier składniowy.
źródło
W niektórych sytuacjach użycie może być dopuszczalne
Object.create
. Odwołanie do Mozilli zawiera polifill, jeśli potrzebujesz kompatybilności wstecznej lub chcesz uruchomić własną funkcję inicjalizacyjną.Dotyczy twojego przykładu:
Przydatne scenariusze
W moim przypadku uznałem to za przydatne w testach jednostkowych z dwóch powodów:
__proto__
) i zawieść test. Na przykład:Wynik niepowodzenia testu jednostkowego nie dostarczy pojęcia o tym, co jest niezgodne.
Wreszcie rozwiązanie zaproponowane na stronie http://typescript.codeplex.com/workitem/334 nie obsługuje wbudowanej deklaracji typu json. Na przykład nie można skompilować:
źródło
Chciałem rozwiązania, które miałoby następujące:
Oto jak to robię:
Wszystkie właściwości konstruktora są obowiązkowe i nie można ich pominąć bez błędu kompilatora.
To zależy od tego,
OnlyData
który filtrujegetFullName()
wymagane właściwości i jest zdefiniowane w następujący sposób:Obecne ograniczenia tego sposobu:
źródło
To jest inne rozwiązanie:
źródło
Możesz mieć klasę z opcjonalnymi polami (oznaczonymi?) I konstruktor, który odbiera instancję tej samej klasy.
W takim przypadku nie będzie można pominąć wymaganych pól. Zapewnia to precyzyjną kontrolę nad konstrukcją obiektu.
Możesz użyć konstruktora z typem Częściowym, jak zauważono w innych odpowiedziach:
Problem polega na tym, że wszystkie pola stają się opcjonalne i w większości przypadków nie jest pożądane.
źródło
Najłatwiej to zrobić za pomocą rzutowania typu.
źródło
MyClass
?Jeśli używasz starej wersji maszynopisu <2.1, możesz użyć podobnej do poniższej, która polega na rzutowaniu dowolnego na wpisany obiekt:
źródło
jeśli chcesz utworzyć nowe wystąpienie bez ustawiania wartości początkowej, gdy wystąpienie
1- musisz użyć klasy, a nie interfejsu
2- musisz ustawić wartość początkową podczas tworzenia klasy
źródło