Comment initier une nouvelle classe de TS
cette manière (exemple C#
pour montrer ce que je veux):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
[modifier]
Lorsque j'écrivais cette question, j'étais un développeur .NET pur sans beaucoup de connaissances JS. De plus, TypeScript était quelque chose de complètement nouveau, annoncé comme un nouveau surensemble de JavaScript basé sur C #. Aujourd'hui, je vois à quel point cette question était stupide.
Quoi qu'il en soit, si quelqu'un cherche toujours une réponse, veuillez consulter les solutions possibles ci-dessous.
La première chose à noter est que dans TS, nous ne devons pas créer de classes vides pour les modèles. Le meilleur moyen est de créer une interface ou un type (selon les besoins). Bon article de Todd Motto: https://ultimatecourses.com/blog/classes-vs-interfaces-in-typescript
SOLUTION 1:
type MyType = { prop1: string, prop2: string };
return <MyType> { prop1: '', prop2: '' };
SOLUTION 2:
type MyType = { prop1: string, prop2: string };
return { prop1: '', prop2: '' } as MyType;
SOLUTION 3 (quand vous avez vraiment besoin d'un cours):
class MyClass {
constructor(public data: { prop1: string, prop2: string }) {}
}
// ...
return new MyClass({ prop1: '', prop2: '' });
ou
class MyClass {
constructor(public prop1: string, public prop2: string) {}
}
// ...
return new MyClass('', '');
Bien sûr, dans les deux cas, vous n'aurez peut-être pas besoin de types de conversion manuellement car ils seront résolus à partir du type de retour de fonction / méthode.
la source
return new MyClass { Field1: "ASD", Field2: "QWE" };
Réponses:
Mettre à jour
Depuis la rédaction de cette réponse, de meilleurs moyens sont apparus. Veuillez voir les autres réponses ci-dessous qui ont plus de votes et une meilleure réponse. Je ne peux pas supprimer cette réponse car elle est marquée comme acceptée.
Ancienne réponse
Il existe un problème sur le codeplex TypeScript qui décrit ceci: Prise en charge des initialiseurs d'objets .
Comme indiqué, vous pouvez déjà le faire en utilisant des interfaces dans TypeScript au lieu de classes:
la source
Person
, mais ce n'est pas du tout une instance dePerson
. Imaginez qu'enPerson
fait, ce serait une classe avec un constructeur complexe et un tas de méthodes, cette approche tomberait à plat sur le visage. C'est bien qu'un groupe de personnes ait trouvé votre approche utile, mais ce n'est pas une solution à la question telle qu'elle est énoncée et vous pourriez tout aussi bien utiliser une personne de classe dans votre exemple au lieu d'une interface, ce serait le même type.Mise à jour le 12/07/2016: Typescript 2.1 présente les types mappés et fournit
Partial<T>
, ce qui vous permet de le faire ....Réponse originale:
Mon approche consiste à définir une
fields
variable distincte que vous transmettez au constructeur. L'astuce consiste à redéfinir tous les champs de classe pour cet initialiseur comme facultatifs. Lorsque l'objet est créé (avec ses valeurs par défaut), vous affectez simplement l'objet initialiseur àthis
;ou faites-le manuellement (un peu plus sûr):
usage:
et sortie console:
Cela vous donne une sécurité de base et une initialisation des propriétés, mais tout est facultatif et peut être hors service. Vous obtenez les valeurs par défaut de la classe seuls si vous ne passez pas un champ.
Vous pouvez également le mélanger avec les paramètres de constructeur requis - restez
fields
sur la fin.À peu près aussi proche du style C # que vous allez l'obtenir, je pense ( la syntaxe de l'initialisation sur le terrain a été rejetée ). Je préférerais de loin une initialisation de champ appropriée, mais cela ne semble pas encore arriver.
À titre de comparaison, si vous utilisez l'approche de transtypage, votre objet d'initialisation doit avoir TOUS les champs du type vers lequel vous transtypez, en plus de ne pas obtenir de fonctions (ou dérivations) spécifiques à la classe créées par la classe elle-même.
la source
Partial<>
, justePerson
- cela vous obligera à passer un objet qui a les champs requis. cela dit, voir ici pour des idées (voir Choix) qui limitent le mappage de type à certains champs.public constructor(init?:Partial<Person>) { Object.assign(this, init); }
Vous trouverez ci-dessous une solution qui combine une application plus courte de
Object.assign
pour modéliser plus étroitement leC#
motif d' origine .Mais d'abord, passons en revue les techniques proposées jusqu'à présent, qui comprennent:
Object.assign
Partial<T>
astuce astucieuse dans le constructeur de copieObject.create
au lieu deObject.assign
Bien sûr, chacun a ses avantages / inconvénients. La modification d'une classe cible pour créer un constructeur de copie n'est pas toujours une option. Et le «casting» perd toutes les fonctions associées au type cible.
Object.create
semble moins attrayant car il nécessite une carte de descripteur de propriété assez verbeuse.Réponse la plus courte et polyvalente
Voici donc une autre approche quelque peu plus simple, qui maintient la définition de type et les prototypes de fonctions associés, et modélise plus étroitement le
C#
modèle souhaité :C'est tout. Le seul ajout sur le
C#
motif estObject.assign
accompagné de 2 parenthèses et d'une virgule. Consultez l'exemple de travail ci-dessous pour confirmer qu'il conserve les prototypes de fonction du type. Aucun constructeur requis et aucune astuce intelligente.Exemple de travail
Cet exemple montre comment initialiser un objet à l'aide d'une approximation d'un
C#
initialiseur de champ:la source
Vous pouvez affecter un objet anonyme casté dans votre type de classe. Bonus : Dans Visual Studio, vous bénéficiez de l'intellisense de cette façon :)
Éditer:
AVERTISSEMENT Si la classe a des méthodes, l'instance de votre classe ne les obtiendra pas. Si AClass a un constructeur, il ne sera pas exécuté. Si vous utilisez instanceof AClass, vous obtiendrez faux.
En conclusion, vous devez utiliser l'interface et non la classe . L'utilisation la plus courante concerne le modèle de domaine déclaré comme Plain Old Objects. En effet, pour le modèle de domaine, il vaut mieux utiliser l'interface plutôt que la classe. Les interfaces sont utilisées au moment de la compilation pour la vérification de type et contrairement aux classes, les interfaces sont complètement supprimées pendant la compilation.
la source
AClass
contenaient des méthodes,anInstance
je ne les obtiendrais pas.anInstance instanceof AClass
vous obtiendrezfalse
au moment de l'exécution.Je suggère une approche qui ne nécessite pas Typescript 2.1:
points clés:
Partial<T>
non requisela source
new Person(<Person>{});
(car casting) et pour être clair aussi; l'utilisation de <T> partiel prend en charge les fonctions. En fin de compte, si vous avez des champs obligatoires (plus des fonctions de prototype), vous devrez faire:init: { name: string, address?: string, age: number }
et supprimer le casting.class
alorsvar
, si je le faisvar dog: {name: string} = {name: 'will be assigned later'};
, il compile et fonctionne. Une déficience ou un problème? Oh,dog
a une très petite portée et spécifique, ce qui signifie qu'une seule instance.Je serais plus enclin à le faire de cette façon, en utilisant (éventuellement) des propriétés et des valeurs par défaut automatiques. Vous n'avez pas suggéré que les deux champs font partie d'une structure de données, c'est pourquoi j'ai choisi cette façon.
Vous pouvez avoir les propriétés de la classe, puis les affecter de la manière habituelle. Et évidemment, ils peuvent ou non être nécessaires, c'est donc autre chose aussi. C'est juste que c'est un si bon sucre syntaxique.
la source
Dans certains scénarios, il peut être acceptable d'utiliser
Object.create
. La référence Mozilla inclut un polyfill si vous avez besoin d'une rétrocompatibilité ou si vous souhaitez utiliser votre propre fonction d'initialisation.Appliqué à votre exemple:
Scénarios utiles
Dans mon cas, j'ai trouvé cela utile dans les tests unitaires pour deux raisons:
__proto__
) et échouer au test. Par exemple:La sortie de l'échec du test unitaire ne donnera aucun indice sur ce qui ne correspond pas.
Enfin, la solution proposée sur http://typescript.codeplex.com/workitem/334 ne prend pas en charge la déclaration de style json en ligne. Par exemple, ce qui suit ne se compile pas:
la source
Je voulais une solution qui aurait les éléments suivants:
Voici comment je le fais:
Toutes les propriétés du constructeur sont obligatoires et ne peuvent pas être omises sans une erreur de compilation.
Il dépend de celui
OnlyData
qui filtregetFullName()
les propriétés requises et il est défini comme suit:Limitations actuelles de cette manière:
la source
Voici une autre solution:
la source
Vous pouvez avoir une classe avec des champs facultatifs (marqués avec?) Et un constructeur qui reçoit une instance de la même classe.
Dans ce cas, vous ne pourrez pas omettre les champs obligatoires. Cela vous donne un contrôle fin sur la construction de l'objet.
Vous pouvez utiliser le constructeur avec le type Partiel comme indiqué dans d'autres réponses:
Le problème est que tous les champs deviennent facultatifs et ce n'est pas souhaitable dans la plupart des cas.
la source
La façon la plus simple de procéder consiste à effectuer une conversion de type.
la source
MyClass
?Si vous utilisez une ancienne version de typescript <2.1, vous pouvez utiliser une méthode similaire à la suivante, qui consiste à convertir n'importe quel objet en objet tapé:
la source
si vous souhaitez créer une nouvelle instance sans définir la valeur initiale lors de l'instance
1- vous devez utiliser la classe et non l'interface
2- vous devez définir la valeur initiale lors de la création de la classe
la source