eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
Docspt-BR
Matriz de recursos C# suportados
Edit this page
13 min read
🌐 Esta página em: English · Português
Este documento traz uma lista abrangente dos recursos de C#, APIs .NET e padrões suportados pelo compilador do eQuantic.UI.
LEGENDASuporte completo: transpila para um comportamento JavaScript equivalente. ⚠️ Suporte parcial: funciona com ressalvas ou diferenças pequenas. ❌ Sem suporte: lógica fundamentalmente incompatível (ex.: I/O bloqueante, ponteiros unsafe).
🏗️ Recursos centrais da linguagem
Recurso
Status
Notas
Classes e structs
Transpilados para classes ES6.
Interfaces
Usadas na checagem de tipos do TypeScript (apagadas em runtime).
Enums
Atravessam como o nome em camelCase (MainAlign.Start'start'). .ToString() e interpolação dão o nome do membro C# ("Start"), o mesmo texto que o servidor imprime. Desde 0.2.0-preview.15.
Genéricos
Totalmente suportados (apagados em runtime).
Extension methods
Resolvidos pelo Semantic Model e transpilados para chamadas diretas.
Async / await
Mapeiam para async / await e Promise.
Expressões lambda
Mapeiam para arrow functions () => {}.
Pattern matching
Padrões is, padrões de propriedade, padrões recursivos.
Interpolação de string
Mapeia para template literals ${var} .
Null-coalescing
?? e ??= mapeados para os equivalentes JS.
Inicializadores de objeto
new Obj { Prop = 1 }.
field (C# 14)
Propriedades guardadas: o gêmeo ganha um slot $name (um nome que nenhum campo C# pode ter), um getter e o corpo do próprio acessor.
Acessores init
Emitidos como setter JS, porque um corpo de init é onde um tipo declara a invariante dele, e descartá-lo perderia a checagem no cliente.
Inicializadores de coleção
new List<int> { 1, 2 } mapeia para [1, 2].
Desconstrução
var (a, b) = tuple mapeia para [a, b] = tuple.
Funções locais
Transpiladas para funções internas.
Records (with)
Mapeia para spread de objeto { ...src, prop: val }.
typeof
Mapeia para o literal de string com o nome do tipo.
Chamadas base
Mapeiam para a palavra-chave super.
cast e as
Mapeiam para passagem/truncamento em JS.
sizeof
Mapeia para os tamanhos dos primitivos C#.
Métodos anônimos
delegate(...) { ... } mapeia para arrow functions.
params
Um parâmetro REST (...xs). As duas formas de chamada do C# funcionam: argumentos expandidos e um array passado inteiro, que é espalhado. Desde 0.2.0-preview.15.
stackalloc
Mapeia para typed arrays (ex.: Int32Array).
yield return
Mapeia para generator functions do JS (function*).
lock
⚠️
Transpilado para um bloco sem efeito (JS é single-threaded).
🔄 Suporte a LINQ
O compilador inclui estratégias especializadas para quase todos os métodos LINQ.
Lógica
Métodos
Status
Filtragem
Where, OfType
Projeção
Select, SelectMany, Cast
Particionamento
Skip, Take, SkipWhile, TakeWhile
Ordenação
OrderBy, OrderByDescending, ThenBy, Reverse
Agregação
Count, Sum, Min, Max, Average, Aggregate
Quantificadores
Any, All, Contains
Conjuntos
Distinct, DistinctBy, Union, Intersect, Except, Concat
Elementos
First, FirstOrDefault, Single, Last, ElementAt
Utilitários
SequenceEqual, DefaultIfEmpty
Conversão
ToList, ToArray, ToDictionary, ToHashSet
Agrupamento/Join
GroupBy, Join, Zip
📦 Tipos .NET (BCL)
Mapeamos os tipos .NET comuns para os equivalentes em JavaScript.
Primitivos
Tipo .NET
Equivalente JavaScript
string
String
int, double, float
Number
bool
Boolean
object
Object
dynamic
any
System.String
Join, Format
IsNullOrEmpty, IsNullOrWhiteSpace
Split, Replace, Substring, Trim
ToLower, ToUpper, StartsWith, EndsWith
System.DateTime, TimeSpan, DateOnly, TimeOnly e DateTimeOffset
Os tipos temporais são respaldados por tipos compatíveis com precisão de tick (ticks de 100 ns, calendário gregoriano proléptico, não o mapeamento com perda de new Date() / milissegundos numéricos). Construtores, componentes, Add*, aritmética (-TimeSpan), comparações e o .ToString() invariante batem todos com o .NET; os valores atravessam o fio do SSR como strings ISO-8601 / "c" e são hidratados de volta no tipo compatível. Veja a tabela Cobertura e conformidade da BCL .NET abaixo para o detalhe por tipo.
System.Collections.Generic
List<T> → Array [] do JavaScript
Dictionary<TKey, TValue> → objeto simples {} para chaves string/número/enum; $eq.collections.valueMap para chaves de record/struct/tupla (chaves de igualdade estrutural, então duas chaves iguais por valor colidem como no .NET).
HashSet<T>Set do JavaScript.
ContainsKey / TryGetValue perguntam pela chave própria do objeto, então um dicionário nunca responde por "constructor", "toString" ou qualquer outra coisa em Object.prototype. Desde 0.2.0-preview.15.
Queue<T>, Stack<T>, LinkedList<T>, SortedSet<T>, SortedDictionary<K,V>, SortedList<K,V> → coleções compatíveis do runtime, sob $eq.collections.*.
System.Threading.Tasks
Task, Task<T>Promise.
Task.Delay → wrapper de setTimeout.
Task.WhenAll, Task.WhenAny.
⚠️ Task.Run executa na thread principal (microtask), NÃO numa thread de fundo.
Outros utilitários
Console.WriteLineconsole.log.
Math.* (Min, Max, Abs, Round, etc.) → Math.*.
Guid (NewGuid, Empty, Parse) → crypto.randomUUID().
RegexRegExp do JavaScript.
🌐 Pacotes do ecossistema
eQuantic.UI.Lucide / Heroicons / RadixIcons / TablerIcons / Phosphor / SimpleIcons / BootstrapIcons / Iconoir / ...
Propósito: conjuntos de ícones abrangentes. Contêm:
Lógica de resolução de SVG
Componentes de ícone especializados
Implementação de IIconProvider
Pacote
Propósito
Status
eQuantic.UI.Charts (Apex/ChartJS)
Visualização de alta performance.
eQuantic.UI.Lottie
Animações de alta performance.
eQuantic.UI.Image
Otimizada (Lazy/Blur/Priority).
eQuantic.UI.Tailwind
Integração de estilo padrão.
🧩 Padrões do framework
Padrão
Interface
Descrição
Status
Gestão de metadados
IHandleMetadata
Tags de SEO e elementos do head.
Gestão de assets
IRequireAssets
Injeção dinâmica de script/estilo.
Server Actions
[ServerAction]
RPC seguro do cliente para o servidor.
Componentes compostos
N/A
Padrões de subcomponentes semânticos.
⚠️ Limitações e ressalvas
1.
Código bloqueante:
.Wait() e .Result em Tasks NÃO são suportados. Você tem que usar await. Bloquear a thread principal congela a interface do browser.
2.
Reflexão:
System.Reflection é largamente sem suporte.
typeof(T).Name e nameof(...) são constantes suportadas.
3.
Sistema de arquivos:
System.IO (File, Directory) não é estritamente proibido, mas vai falhar em tempo de execução no browser.
Use Server Actions para lidar com operações de arquivo.
4.
Números:
int/double/float mapeiam para números do JS. A divisão inteira trunca (Math.trunc) e o Math.Round usa arredondamento bancário (MidpointRounding.ToEven) pelo helper compatível round.
decimal é exato de ponta a ponta: compilado para o tipo compatível Decimal do runtime (mantissa BigInt + escala), então 0.1m + 0.2m == 0.3m é true. Decimais também atravessam o fio como strings JSON (EqJson) e são hidratados de volta em Decimal no cliente (o padrão Decimal do campo guia uma coerção que preserva o tipo, veja hydrate-value.ts), então os decimais vindos do servidor mantêm todos os 28 dígitos em vez de arredondar por um double.
long/ulong agora são exatos: compilados para BigInt do JS pelo helper compatível long. 9007199254740993L + 1L é 9007199254740994 (um número JS comum arredondaria para …992). Literais viram BigInt (5L5n); operandos de aritmética/comparação são embrulhados em long() (que coage number/stringbigint) para que expressões mistas nunca lancem. No fio, inteiros de 64 bits atravessam como strings JSON (Server Actions + estado do SSR, via EqJson) para que valores além de 2^53 sobrevivam à ida e volta. Outros sufixos de tipo numérico (1.5f, 100u) são removidos.
5.
Segurança entre threads:
Como o JS é single-threaded, instruções lock são compiladas para fora (ignoradas).
Thread.Sleep não é suportado (use Task.Delay).
🧪 Cobertura e conformidade da BCL .NET
A fidelidade da transpilação é imposta por um arnês de conformidade (tests/eQuantic.UI.Conformance.Tests): cada caso roda a mesma expressão C# de dois jeitos, transpilada para JS (executada pelo Bun embarcado) e avaliada diretamente em .NET (Roslyn scripting), e afirma resultados idênticos. Mais de 460 casos estão verdes.
(Mais recente: dicionários com chave de record via $eq.collections.valueMap.) Isso cobre tanto expressões quanto blocos de instruções (controle de fluxo: if/for/foreach/while/switch/ try-catch-finally/funções locais; o bloco roda numa IIFE e o valor retornado é comparado).
Toda construção resolve por um de três mecanismos (veja docs/DOTNET-COVERAGE-PROGRAM.md):
1.
Estratégia nativa: JS idiomático quando o runtime tem um equivalente.
2.
Helper compatível com .NET no runtime: semântica .NET fiel onde o JS não tem nenhuma. O transpilador emite esses sob um único namespace $eq (organizado por domínio), trazido com **um import por módulo**, import { $eq } from "@equantic/runtime" (resolvido pelo import map da página), em vez de N imports soltos de helpers, e $eq.* nunca pode colidir com um identificador do usuário no escopo gerado:
$eq.num: dec (Decimal exato), long (Int64 via BigInt)
$eq.math: round (arredondamento bancário)
$eq.text: format (formatação de número/string), stringBuilder
$eq.time: dateTime, timeSpan, dateOnly, timeOnly, dateTimeOffset
$eq.enums: parse (nome de membro de enum)
$eq.collections: queue (FIFO), stack (LIFO), valueMap (dicionário com chave estrutural), linkedList, sortedSet/sortedDictionary/sortedList (ordenados por chave)
$eq.nullable: arith, cmp (operadores Nullable<T> elevados: aritmética que propaga nulo, relacional falso em nulo)
$eq.equals: igualdade estrutural (por valor) para records/structs/tuplas (dá suporte a ==, .Equals, Contains, Distinct)
$eq.css: styleBuilder, classBuilder, joinClasses, whenClass (o subsistema de estilo)
3.
Falhar no que não é suportado: uma construção sem representação possível em JS agora levanta um erro de build (com um código EQ estável) em vez de ser emitida verbatim em silêncio. Duas camadas:
UnsupportedConstructStrategy (EQ2001): intrínsecos de referência tipada (__makeref, __refvalue, __reftype), tipos ponteiro, ponteiros de função.
goto/goto case/goto default (EQ2002): sem equivalente em JS; reestruture com laços/condicionais. (Blocos unsafe/fixed/lock desembrulham para o corpo deles, sendo o lock um no-op single-threaded, e um rótulo solto cai para a instrução interna dele.)
Fronteira cliente/servidor do SemanticValidator (EQ21xx): chamadas a System.IO, System.Net.Http, System.Net.Sockets, EF Core / System.Data, threading do SO (Thread/Monitor/Mutex), Process, InteropServices (P/Invoke), Reflection.Emit a partir de um componente cliente. (System.Threading.Tasks não é proibido: async mapeia para Promise.) A correção é mover a chamada para um [ServerAction].
Qualquer outra construção que não bata em nenhuma estratégia é emitida verbatim, mas agora reportada como aviso (EQ1001/EQ1002), para que fique visível em vez de silenciosa. Os diagnósticos saem na forma canônica do MSBuild, então erros falham o dotnet build.
Área
Status
Notas
Aritmética / bitwise / comparação
a divisão inteira trunca; %, deslocamentos, & | ^ ~ nativos; checked(expr) lança OverflowException, unchecked(expr) dá a volta em 32 bits (\| 0/>>> 0). Estouro de int no contexto padrão não dá a volta (float64 do JS).
Math.*
Truncatetrunc, Ceilingceil, Round bancário pelo helper round
decimal
exato via Decimal (literais + + - * / == != < > <= >=)
Constantes numéricas
int.MaxValue, double.Epsilon, … → literais
Parsing / Convert.*
int/double.Parse, bool.Parse, Convert.ToInt32/ToDouble/ToString/ToBoolean/…
Strings
Substring/IndexOf/Replace/Split/Pad/Trim(char)/Concat/Format/Join/IsNullOrEmpty/IsNullOrWhiteSpace; Equals/StartsWith/EndsWith/Contains/IndexOf cientes de StringComparison (Ordinal + IgnoreCase). Ordenação sensível à cultura (CompareTo) está fora de escopo.
char.*
ToUpper/ToLower/IsDigit/IsLetter/IsWhiteSpace/… (cientes de Unicode)
StringBuilder
tipo compatível: Append(incl. bool→"True"/"False")/AppendLine("\n")/Insert/Remove/Replace/Clear/Length/ToString
LINQ
Where/Select/SelectMany/Where-Select(indexado)/OrderBy/Distinct(By)/GroupBy/ToDictionary/ToLookup/Zip/Chunk/MinBy/MaxBy/Take(While)/Skip(While)/Aggregate/Sum/Min/Max/Average/Count/Any/All/First/Last/Concat/Reverse/Join/GroupJoin/ThenBy/ThenByDescending (Join/GroupJoin = hash join que preserva a ordem sobre chaves primitivas; OrderBy+ThenBy = uma única ordenação composta estável, com a fonte copiada). O IGrouping vindo de GroupBy/ToLookup é usável como sequência (iterar, g.Select/g.Sum/g.Count()) e expõe g.Key; o indexador [key] de ILookup não é modelado.
Coleções
List, Dictionary, HashSet (incl. inicializadores e .Count); compatíveis de Queue/Stack/LinkedList; família ordenada SortedSet/SortedDictionary/SortedList (enumeração ordenada por chave). Dicionários com chave de record/struct/tupla vão para $eq.collections.valueMap (chaves estruturais: construção, get/set em d[k], ContainsKey/Add/Remove/Clear/TryGetValue/GetValueOrDefault, Keys/Values/Count, foreach); dicionários com chave string/número/enum mantêm a forma de objeto simples. O indexador ILookup[key] devolve o grupo (ou vazio para uma chave ausente).
enum
string com o nome do membro (igualdade/switch/ternário)
long/ulong
exato via BigInt (helper long); literais 5L5n, no fio como string JSON
DateTime
tipo compatível DateTime com precisão de tick: construtores, componentes, Add*, -TimeSpan, comparações, .ToString()/format; fio ISO-8601 + hidratação
TimeSpan
tipo compatível TimeSpan com precisão de tick: From*, construtores, componentes/totais, + -, comparações, .ToString() "c" do .NET; fio "c" + hidratação
DateOnly / TimeOnly
tipos compatíveis (.NET 6+): construtores, componentes, Add*(+ volta do TimeOnly), comparações, .ToString() invariante (MM/dd/yyyy / HH:mm); fio ISO + hidratação
DateTimeOffset
tipo compatível com precisão de tick (hora de parede + deslocamento, comparado pelo instante): construtores, componentes, Offset/UtcDateTime/LocalDateTime, ToOffset, Add*, From/ToUnixTime*, - TimeSpan, comparações por instante, .ToString() invariante (MM/dd/yyyy HH:mm:ss zzz); fio ISO+offset + hidratação
record / struct / tupla de valor
Semântica de valor. Records/structs são objetos simples (o posicional new Point(1,2){x,y}, inicializadores de objeto mesclam), tuplas são arrays com acesso a elemento por posição (t.Item1) e por nome declarado ((int X, int Y).X) → índice. ==/!=, .Equals, Contains, Distinct comparam estruturalmente via $eq.equals; o with copia e substitui. A desconstrução var (a, b) = … funciona para tuplas (destructuring de array, com buracos de descarte) e records (destructuring de objeto pela ordem do Deconstruct). Records são emitidos como classes JS nomeadas, carregando os métodos de instância do usuário + um equals estrutural, um with que preserva o protótipo, e o toString do .NET; a semântica de valor não muda. O pipeline de build descobre records por varredura e emite cada um como módulo próprio; componentes que referenciam um record o importam automaticamente (reativo, sem lista fixa). Os valores do SSR são re-hidratados de volta na classe do record no cliente (recursivamente, restaurando records aninhados e membros compatíveis), então métodos/instanceof sobrevivem. Cobre records posicionais e de corpo e structs simples (a construção por inicializador de objeto mapeia para o construtor pela ordem dos membros, com padrões por membro), mais herança de record (extends + super) e records genéricos (argumentos de tipo apagados). Dicionários com chave de record (Dictionary<RecordKey, V>) vão para $eq.collections.valueMap, para que chaves iguais por valor colidam como no .NET.
Nullable<T> (T?)
HasValue/Value, GetValueOrDefault() (padrão ciente do tipo: 0/false/$eq.num.dec(0)/membro zero do enum/…) e GetValueOrDefault(fallback), ??; operadores elevados via $eq.nullable.*: a aritmética propaga null, o relacional (< > <= >=) é falso quando qualquer lado é nulo (não uma coerção numérica). O GetValueOrDefault() sem argumento em DateTime?/Guid?/struct devolve null, então use a forma com fallback ali.
Guid
Guid.NewGuid()crypto.randomUUID(), Guid.Empty, Guid.Parse; fio como string