Schnelleinstieg in TypeScript
Inhaltsverzeichnis
Get Started
Als VBS- oder C#-Programmierer sollte dir der Umstieg zu TypeScript sicherlich leicht fallen. Der große Vorteil von TypeScript ist, wie es der Name bereits verrät, dass TypeScript eine streng typisierte Programmiersprache ist, welche auf JavaScript aufbaut. Die offizielle Dokumentation der TypeScript Language bietet uns sehr gute Inhalte für Einsteiger sowie Programmierer mit Vorwissen (z.B. aus VBS/C#).
Einen Playground zum Ausführen eigener Snippets findest du dort ebenfalls: Playground
Einsteiger Tutorial
Eine Anleitung für Beginner auf Englisch findest du hier (empfohlen) Eine Anleitung für Beginner auf Deutsch findest du hier
Tutorial für Fortgeschrittene
Du hast bereits Vorkenntnisse in JavaScript oder VB-Skript (mit ein wenig Umdenken)? Perfekt! Einen Guide für den Umstieg zu TypeScript findest du hier. C# ist genau dein Ding? Hier geht es zum Umstieg von C# auf TypeScript
TypeScript meets combit CRM → Das cosmolink TypeScript SDK und lib
Doch am Ende gilt: Learning by doing! Die Offizielle Dokumentation, Hinweise, Hilfestellungen usw. findest du unter https://www.typescriptlang.org/
Variablen, Parameter und private Properties schreibt man in TypeScript grundsätzlich in lowerCamelCase.
Funktionen und Klassen werden üblicherweise in PascalCase notiert.
Cheat Sheet's
https://devhints.io/typescript https://www.typescriptlang.org/cheatsheets
Perfekt! Damit bist du quasi dafür bereit, dein erstes ts-Skript zu schreiben.
Um dir dein Leben etwas einfacher zu machen, haben wir das cosmolink TypeScript SDK und Library für dich erstellt. Diese beinhalten nützliche Funktionen rund um den combit CRM für dein every-day Coding.
Die Dateien findest du im Solutionordner unter \Script\Typescript\SDK bzw. \Script\TypeScript\lib. Eine ausführliche Dokumentation unserer Libraries findest du hier.
Erstellen eines Skripts
Damit die referenzierten Module von deinem Skript gefunden werden können, ist es notwendig, dass du dein Skript im TypeScript-Verzeichnis der jeweiligen Solution erstellst bzw. ausführst!
Skriptzeilen ausführen
Um Code in Skriptzeilen ausführen zu können, benötigst du ein #language-Attribut am Anfang des Skripts. Das geht wie folgt:
<!--#language="Cosmolink.TypeScript"-->
import { cRM } from './SDK/Cosmolink.Scripting.SDK.CRMApplication';
import { CRMContext } from "./lib/CRMContext";
await using cRM_Context = new CRMContext(cRM);
Der CRM_Context stellt uns dabei die CRM- Objekte bereit. In unserem Beispiel den direkten Zugriff auf den CurrentRecord der ActiveView.
Objekttypen und Zuweisung
const currentRecord: Record = await cRM_Context.CurrentRecord;
Welche Funktionen es im CRM_Context sonst noch gibt kannst du direkt in der Library nachlesen. In vielen Fällen ersetzt dies komplette Snippets, welche du noch aus VB-Skript kennst.
Weitere Beispiele für den CRM_Context
Prüfen der aktiven Ansicht
// Prüfen der aktiven Ansicht
const receiptViewName : string = `FakturaBelege`;
if (! await cRM_Context.HasActiveView())
{
throw new Error(`Für die Skriptausführung ist eine aktive Ansicht notwendig.`);
}
if (! await cRM_Context.IsActiveView(receiptViewName))
{
throw new Error(`Die Funktion kann nur aus der Ansicht ${receiptViewName} ausgeführt werden.`);
}
Auslesen der Standardwährung
async function GetDefaultCurrencyAsync(): Promise<number>
{
const currencyRecordSet = await cRM_Context.GetRecordSet(`FakturaWährungen`, RecordSetFilterType.SetFilterDirectSQL, `SELECT fw.Recordid FROM dbo.Factura_Waehrungen fw WHERE fw.Standard = 1`);
if (currencyRecordSet == null )
{
throw new Error(`Beim Auslesen der Standardwährung ist ein unerwartetes Verhalten aufgetreten.`);
}
if (! await currencyRecordSet.MoveFirst())
{
// return Euro if default is not set
return 1 ;
}
const defaultCurrencyRecord: Record = await currencyRecordSet.CurrentRecord;
return await defaultCurrencyRecord.GetContentsValueByName(CLType.Number ,`ID`);
}
Öffnen einer Datensatzauswahl
async function SelectRecordAsync(viewName: string, filterType: RecordSetFilterType, filter: string, windowTitle: string = `Bitte wählen Sie einen Datensatz aus.`): Promise<Record>
{
const recordSet: RecordSet = await cRM_Context.GetRecordSet(viewName, filterType, filter);
try
{
if (recordSet == null )
{
throw new Error(`Beim Erstellen des Filters auf die ${viewName} ist ein unerwartetes Verhalten aufgetreten.`);
}
return await recordSet.DialogSelectRecord(windowTitle, true);
}
finally
{
await recordSet?.DisposeAsync();
}
}
Weitere Beispiele CRMApplication MsgBoxButton und MsgBoxIcon
await cRM.DialogMessageBox(`Der Vorgang wird beendet.`, `Es konnte nicht auf den aktuellen Datensatz zugegriffen werden.`, `cosmolink`, MsgBoxButton.OkOnly, MsgBoxIcon.Exclamation);
Async und Await
Wie du in den oben genannten Beispielen sicherlich schon mitbekommen hast, gibt es in TypeScript genau wie in C# asynchrone Codeausführungen. Grundsätzlich ist es so, dass vor allem bei API Calls nicht immer bekannt ist, wann eine Returnvalue zurück kommt.
Beispiel: Wir möchten uns von der Wetter.com API das aktuelle Wetter ziehen. Hierfür machen wir eine HTTP Request.
Die HTTP Request machen wir also bei externen Ressourcen, von denen wir nicht wissen wie lange sie benötigen, um uns das Result bereitzustellen.
Der Code wird bei der synchronen Ausführung weiterlaufen, egal ob wir bereits ein Result haben oder nicht. Das kann zu Fehlern führen!
Aus diesem Grund "warten" (awaiten) wir die asynchrone Funktion, hierfür benutzen wir die ASYNC und AWAIT Keywords.
// synchronous
function GetWeather(target: string, type: LocationType) {
const dto = queryApi(target, type);
// dto might be empty at this point because we're not awaiting the API result
return parseWeatherDto(dto);
}
// asynchronous
async function GetWeatherAsync(target: string, type: LocationType) {
const dto = await queryApi(target, type);
// await ensures that we completed the execution of queryApi()
return parseWeatherDto(dto);
}
MsgBoxButton und MsgBoxIcon
await cRM.DialogMessageBox(`Der Vorgang wird beendet.`, `Es konnte nicht auf den aktuellen Datensatz zugegriffen werden.`, `cosmolink`, MsgBoxButton.OkOnly, MsgBoxIcon.Exclamation);
Using und Await Using
In TypeScript gibt es ebenfalls wie in C# das using-Statement. (Ab Version 5.2 , welche wir nutzen)
Using bedeutet, dass eine Variablendefinition nach Verlassen ihres Scopes automatisch freigegeben (disposed) wird. Deutlich wird dies an folgendem Beispiel:
import { CRMContext } from "./lib/CRMContext";
// der erstellte cRM_Context ist im globalen Scope und wird bei Verlassen des Skripts automatisch freigegeben
await using cRM_Context = new CRMContext(cRM);
try
{
await main();
}
catch (error)
{
if (error instanceof (Error))
{
await cRM.DialogMessageBox(`Der Vorgang wird beendet.`, error.message, `cosmolink`, MsgBoxButton.OkOnly, MsgBoxIcon.Exclamation);
}
}
// cRM_Context wird freigegeben
async function main(): Promise<void>
{
// das erstellte Projekt "project" ist im Scope der main()-Function und wird bei Verlassen der main()-Function freigegeben
await using project : Project = await cRM_Context.Project;
if (project == null)
{
throw new Error(`Beim Auslesen des Projekts ist ein unerwartetes Verhalten aufgetreten. Bitte führen Sie das Skript in einer geöffneten Solution aus.`);
}
await cRM.DialogMessageBox(`Vorgang erfolgreich!`, `TypeScript konnte erfolgreich mit dieser Solution ausgeführt werden`, `cosmolink`, MsgBoxButton.OkOnly, MsgBoxIcon.Information);
// project wird freigegeben
}
Errorhandling
Errorhandling in TypeScipt funktioniert ähnlich dem Errorhandling in C#. Hier für können wir Try-Catch-Finally Blöcke verwenden.
Try Catch Finally
import { CRMContext } from "./lib/CRMContext";
await using cRM_Context = new CRMContext(cRM);
try
{
await main();
}
catch (error)
{
// Prüfen, ob der geworfene error vom Typ Error ist, sonst bekommen wir einen Typenkonflikt
if (error instanceof (Error))
{
await cRM.DialogMessageBox(`Der Vorgang wird beendet.`, error.message, `cosmolink`, MsgBoxButton.OkOnly, MsgBoxIcon.Exclamation);
}
}
async function main(): Promise<void>
{
throw new Error(`Beschreibung - Provozierter Error`);
await cRM.DialogMessageBox(`Aufruf main()`, `Hier kommen wir nicht rein, weil vorher ein Error geworfen wird.`, `cosmolink`, MsgBoxButton.OkOnly, MsgBoxIcon.Exclamation);
return;
}
Zuerst wird versucht den try-Block auszuführen. Wird hierbei ein Error geworfen, springt das Skript automatisch in den catch-Block. Hier können Errors behandelt werden oder im Fehlerfall andere Aktionen aufgerufen werden.
Abschließendes
Bei technischen Fragen, Feedback zur Anleitung oder Erweiterungswünschen kannst du dich gerne an uns wenden!