Working with Data
This page covers how C# data types are represented in the JavaScript Transpose emits — which matters both for performance and for what crosses the interop boundary cleanly.
Primitive types
| C# type | JavaScript representation | Notes |
|---|---|---|
string |
string |
UTF-16, same as .NET |
bool |
boolean |
|
byte, sbyte |
number |
Integer arithmetic, truncated to range |
short, ushort |
number |
|
int, uint |
number |
|
float, double |
number |
IEEE 754, exactly as .NET |
char |
number |
A UTF-16 code unit |
long, ulong |
System.Int64 object |
64-bit exact; not a JS number |
decimal |
System.Decimal object |
Exact decimal arithmetic; not a JS number |
IntPtr, UIntPtr |
— | No browser equivalent |
Integers
A JavaScript number is a 64-bit float, so it represents every 32-bit integer
exactly. Transpose emits the truncation and wrap-around that C# integer arithmetic
requires, so int overflow behaves the way it does on .NET rather than silently
turning into a float.
long and decimal are objects
This is the mapping most worth knowing. long and decimal cannot be held
exactly in a JavaScript number, so the runtime implements them as real types
(System.Int64 and System.Decimal) with their full .NET arithmetic. Two
consequences:
- No precision loss.
longis exact to 64 bits;decimaldoes exact decimal arithmetic. Money and identifiers survive round trips. - They are objects at the interop boundary. A
longhanded to a JavaScript library is not a number, andJSON.stringifywill not serialize it as one. Convert at the boundary —(double)valuewhen the range is safe,value.ToString()when it is not — or keep such fields asstringin the DTOs you exchange with JavaScript.
Arithmetic on long and decimal also allocates and goes through method calls
rather than compiling to a machine operation. Prefer int/double in a hot loop.
Arrays
C# arrays map to JavaScript arrays.
int[] numbers = new int[] { 1, 2, 3 };
var numbers = [1, 2, 3];
Indexing and Length work as expected. A JavaScript array is growable while a C#
array is fixed-size — Transpose does not add a runtime guard for that, so code
that reaches into the array from JavaScript and pushes onto it will produce an
array longer than its C# Length implies.
Multidimensional arrays (int[,]) are represented with the runtime's own array
type rather than a nested JavaScript array, so they do not cross the interop
boundary as plainly as a single-dimensional array does.
Span<T> and ReadOnlySpan<T> are represented as the underlying array. Note that
the implicit array-to-Span<T> conversion is not modelled — Span<int> s = new int[3];
does not produce a working span. Use the array directly.
Collections
The runtime implements the standard generic collections — List<T>,
Dictionary<TKey, TValue>, HashSet<T>, Queue<T>, Stack<T>,
SortedDictionary<TKey, TValue>, LinkedList<T> — with .NET semantics, including
correct key equality (Equals/GetHashCode) for dictionary and set keys.
var list = new List<string> { "a", "b" };
list.Add("c");
var dict = new Dictionary<string, int>();
dict["key"] = 123;
These are runtime objects, not plain JavaScript values: a List<T> is not a
JavaScript array and a Dictionary<K,V> is not a plain object. To hand a
collection to JavaScript, project it first — list.ToArray() for an array, or
build an [ObjectLiteral] type for a map-shaped payload. See
JSON Serialization.
DateTime and TimeSpan
System.DateTime is backed by JavaScript's Date and exposes the .NET API on top
of it — components, arithmetic, Kind, parsing and format strings.
System.TimeSpan is its own runtime type.
Because the underlying Date has millisecond resolution, DateTime.Ticks is
exact only to the millisecond; sub-millisecond precision is not preserved. The
browser's time zone is what DateTime.Now and local-time conversions use, and
there is no time-zone database, so TimeZoneInfo lookups for arbitrary zones are
not available. Work in UTC and format for display.
Guid
System.Guid is implemented, including NewGuid(), parsing, and the standard
format strings. It is a runtime object, so serialize it as a string when crossing
into JavaScript.
Strings, text and regular expressions
string is a JavaScript string, so it is cheap to pass across the boundary. The
runtime implements the .NET string API on top of it — including composite
formatting (string.Format, interpolated strings) and the numeric/date format
specifiers.
System.Text.RegularExpressions is implemented over the JavaScript regular
expression engine. Most patterns behave the same, but .NET-only constructs
(balancing groups, some lookbehind forms, and RegexOptions that have no
JavaScript flag) are not available.