@@ -53,12 +53,236 @@ If you haven't worked with TypeScript tooling before, you'll need a `tsconfig.js
5353```
5454
5555
56- ## Documentation
56+ ## Form Scripting
57+
58+ XrmTypeScript generates form-specific TypeScript interfaces for your Dynamics 365 forms,
59+ giving you full intellisense and type safety.
60+
61+ ### Specific Account Form Example
62+
63+ In this example, we want to add code to the standard Account form called
64+ 'Information', which is of the 'Main' form type. This can be found at
65+ ` Form/account/Main/Information.d.ts ` . Simply by adding this to your TypeScript context,
66+ you get access to the specific Xrm object model API for that form.
67+
68+ #### JavaScript
69+
70+ Use JSDoc comments to get intellisense and type support:
71+
72+ ``` javascript
73+ /**
74+ * @param {Xrm.Events.LoadEventContext} executionContext
75+ */
76+ function onLoad (executionContext ) {
77+ /** @type {Form.account.Main.Information} */
78+ let form = executionContext .getFormContext ();
79+ // Code here..
80+ form .getAttribute (" accountnumber" ).addOnChange (checkAccount);
81+ }
82+
83+ /**
84+ * @param {Xrm.ChangeEventContext<Form.account.Main.Information>} executionContext
85+ */
86+ function checkAccount (executionContext ) {
87+ let form = executionContext .getFormContext ();
88+ // Code here..
89+ let accountNumber = form .getAttribute (" accountnumber" ).getValue ();
90+ }
91+ ```
92+
93+ #### TypeScript
94+
95+ ``` typescript
96+ function onLoad(executionContext : Xrm .LoadEventContext ) {
97+ let form: Form .account .Main .Information = executionContext .getFormContext ();
98+ // Code here..
99+ form .getAttribute (" accountnumber" ).addOnChange (checkAccount );
100+ }
101+
102+ function checkAccount(executionContext : Xrm .ChangeEventContext <Form .account .Main .Information >) {
103+ let form = executionContext .getFormContext ();
104+ // Code here..
105+ let accountNumber = form .getAttribute (" accountnumber" ).getValue ();
106+ }
107+ ```
108+
109+ > Remember to tick ** Pass execution context as first parameter** in CRM when adding your function to the form.
110+
111+ ### Type Safety
112+
113+ In your desired IDE, you will now get intellisense for that specific
114+ account form, with all of its attributes, controls, tabs and sections.
115+
116+ Each attribute and control on the form has the correct type, giving you type safety on values and functions.
117+ If an invalid string is entered as an argument to one of the string-specific functions, the compiler will
118+ show an error — making it easy to catch incorrect attribute names or attempts to access elements that are
119+ not present on the form.
120+
121+
122+ ## Web API & Entities
123+
124+ XrmTypeScript generates TypeScript interfaces that precisely reflect the structure of data returned
125+ by the Dataverse OData endpoint. Every entity in your solution gets its own set of interfaces —
126+ one for retrieval, one for create, and one for update — each typed to the exact shape the API
127+ expects or returns.
128+
129+ This means you get full compile-time safety across your entire data layer: the correct property
130+ names and types on retrieved records, typed nested objects for deep insert, the ` @odata.bind `
131+ syntax for associating existing records, formatted values and lookup metadata available as typed
132+ properties, and relationship traversal with full intellisense on related records. Mistakes that
133+ would previously only surface at runtime are caught by the compiler before they reach your CRM instance.
134+
135+ The generated interfaces work anywhere you query the Dataverse API — on forms via ` Xrm.WebApi ` ,
136+ in PCF components, or in external TypeScript projects using ` fetch ` or any HTTP client.
137+
138+ ### Retrieve
139+
140+ ``` typescript
141+ // Using Xrm.WebApi
142+ const contact: WebApi .Contact = await Xrm .WebApi .retrieveRecord (" contact" , id , options );
143+
144+ // Using fetch
145+ const response = await fetch (` /api/data/v9.2/contacts(${id })${options } ` );
146+ const contact: WebApi .Contact = await response .json ();
147+
148+ // TypeScript knows birthdate is Date | null | undefined
149+ const birthdate = contact .birthdate ;
150+ // Formatted values are typed as string | undefined
151+ const formattedBirthdate = contact [" birthdate@OData.Community.Display.V1.FormattedValue" ];
152+
153+ // Lookup — intellisense shows all SystemUser properties
154+ const createdBy = contact .createdby ;
155+ const createdByName = createdBy ?.nickname ;
156+
157+ // Related collection — each account is fully typed as WebApi.Account
158+ const accounts = contact .account_primary_contact ;
159+ accounts ?.forEach ((account ) => {
160+ const name = account .name ; // string | null | undefined
161+ const shippingMethodFormatted = account [" address2_shippingmethodcode@OData.Community.Display.V1.FormattedValue" ];
162+ });
163+ ```
164+
165+ ### Create
166+
167+ ``` typescript
168+ const newContact: WebApi .Contact .Create = {
169+ firstname: " John" ,
170+ lastname: " Doe" ,
171+ emailaddress1: " john.doe@example.com" ,
172+ birthdate: new Date (" 1990-01-01" ),
173+ // Deep insert — compiler enforces the shape of the nested Account
174+ parentcustomerid_account: {
175+ creditlimit: 10000 ,
176+ name: " Contoso" ,
177+ }
178+ };
179+
180+ // Using Xrm.WebApi
181+ await Xrm .WebApi .createRecord (" contact" , newContact );
182+
183+ // Using fetch
184+ await fetch (" /api/data/v9.2/contacts" , {
185+ method: " POST" ,
186+ headers: { " Content-Type" : " application/json" },
187+ body: JSON .stringify (newContact ),
188+ });
189+ ```
190+
191+ ### Update
192+
193+ ``` typescript
194+ const updatedContact: WebApi .Contact .Update = {
195+ firstname: " Jane" ,
196+ lastname: " Smith" ,
197+ emailaddress1: " jane.smith@example.com" ,
198+ // @odata.bind — typed as a template literal to enforce the correct URL format
199+ " parentcustomerid_account@odata.bind" : " /accounts(00000000-0000-0000-0000-000000001234)" ,
200+ };
201+
202+ // Using Xrm.WebApi
203+ await Xrm .WebApi .updateRecord (" contact" , " 00000000-0000-0000-0000-000000000001" , updatedContact );
204+
205+ // Using fetch
206+ await fetch (" /api/data/v9.2/contacts(00000000-0000-0000-0000-000000000001)" , {
207+ method: " PATCH" ,
208+ headers: { " Content-Type" : " application/json" },
209+ body: JSON .stringify (updatedContact ),
210+ });
211+ ```
212+
213+
214+ ## Tool Arguments
215+
216+ Arguments can be passed via the ` XrmTypeScript.exe.config ` file or directly from the command line.
217+
218+ ### Arguments
219+
220+ #### Connection
221+
222+ | Argument | Short-hand | Description |
223+ | :--------------- | :--------- | :------------------------------------------- |
224+ | url | | URL to the organization |
225+ | method | m | OAuth, ClientSecret or ConnectionString |
226+ | appId | id | Azure Application Id |
227+ | clientSecret | cs | Client secret for the Azure Application |
228+ | returnUrl | | Return URL of the Azure Application |
229+ | connectionString | | Connection String used for authentication |
230+ | username | u, usr | Username for the CRM system |
231+ | password | p, pwd | Password for the CRM system |
232+ | domain | d, dmn | Domain for the user |
233+ | ap | | Authentication Provider Type |
234+
235+ #### Generation
236+
237+ | Argument | Short-hand | Description |
238+ | :---------------- | :--------- | :--------------------------------------------------------------------------------------------------------------- |
239+ | out | o | Output directory for the generated declaration files |
240+ | solutions | ss | Comma-separated list of solution names. Generates code for the entities found in these solutions. |
241+ | entities | es | Comma-separated list of entity logical names. Additive with the entities retrieved via the ` solutions ` argument. |
242+ | web | w | Set to true to generate declaration files for Web entities |
243+ | skipXrmApi | sxa | Set to true to skip generation of Xrm.WebApi overloads |
244+ | crmVersion | cv | Version of CRM to generate declaration files for |
245+ | oneFile | of | Set to true to put all dynamic parts of the generated declarations into a single file |
246+ | skipForms | sf | Set to true to skip generation of form declaration files |
247+ | skipInactiveForms | sif | Set to true to avoid generating types for inactive forms |
248+ | useDeprecated | ud | Set to true to include typings for deprecated functionality |
249+ | useconfig | uc | Also applies the arguments found in the ` .config ` file |
250+
251+ You can also view this list of arguments using the ` /help ` argument.
252+
253+ ### Command Line
254+
255+ ``` bash
256+ XrmTypeScript.exe /url:https://INSTANCE.crm4.dynamics.com /method:ClientSecret /id:< APP_ID> /cs:< CLIENT_SECRET>
257+ ```
258+
259+ If you want to use a mix of the arguments from the configuration file and arguments passed to the executable,
260+ you can use the ` /useconfig ` argument from the command-line.
261+
262+ ``` bash
263+ XrmTypeScript.exe /useconfig /entities:account,contact
264+ ```
265+
266+
267+ ## XrmTypeScript vs XrmDefinitelyTyped
268+
269+ XrmTypeScript is a fork of [ XrmDefinitelyTyped] ( https://github.com/delegateas/XrmDefinitelyTyped ) by Delegateas.
270+ The following is a list of the key differences.
271+
272+ ### What's Different
273+
274+ - ** Modern type foundation** — Xrm types are based on the modern [ ` @types/xrm ` ] ( https://www.npmjs.com/package/@types/xrm ) library.
275+ - ** Non-English support** — Support for non-English environments.
276+ - ** Improved generation performance** — Type generation is significantly faster for solutions with large numbers of entities.
277+ - ** No bundled JavaScript library** — XrmQuery and its runtime dependencies have been removed. XrmTypeScript generates types only, with no runtime overhead.
278+ - ** OData-aligned entity interfaces** — The generated entity interfaces reflect the actual structure of data returned by the Dataverse OData endpoint, making them directly usable with ` Xrm.WebApi ` or any HTTP client.
279+ - ** Xrm.WebApi overloads** — XrmTypeScript generates typed overloads for the native ` Xrm.WebApi ` methods.
280+ - ** Richer generated output** — Types include comments with display names, column types, and enum links, making the generated code more informative in your IDE.
281+ - ** ` getAttribute ` and ` getControl ` work with arrays of field names** — Iterating over a list of known field names correctly resolves each return type, instead of falling through to ` undefined ` .
282+ - ** Attribute and control mappings are always generated** — The ` generateMappings ` argument has been removed. Mappings are now included in the generated output by default.
283+ - ** ` -web ` argument** — Accepts a boolean instead of a namespace string. The generated entity interfaces are placed in the ` WebApi ` namespace by default.
284+ - ** View generation removed** — The ` -views ` argument and generation have been removed.
57285
58- - [ Tool Arguments] ( docs/tool-arguments.md )
59- - [ Form Scripting] ( docs/form-scripting.md )
60- - [ Web API & Entities] ( docs/web-api.md )
61- - [ Comparison with XrmDefinitelyTyped] ( docs/comparison.md )
62286
63287## Acknowledgements
64288
0 commit comments