You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Should we allow to disable reflection on a specific type? #4241
error FABLE: Cannot get type info of generic parameter T. Fable erases generics at runtime, try inlining the functions so generics can be resolved at compile time.
This is because, here Func : TypeA<unit> has a concrete type giving.
However, for a library I am working on I kind of need this type of code supported.
A workaround, is to enable --noReflection flag in Fable but it means not reflection can happen anywhere, so perhaps it could be nice to introduce a [<NoReflection>] attribute to disable it only for specific types.
Another workaround is to use an anonymous record:
typeUpdates={|
VarView :TypeA<unit>|}
I will see if I can rewrite my library to use the anonymous record, as it would be better to not introduce an attribute for a really specific usage.
Here's a technical analysis of the options for this request.
Current behaviour
Fable's reflection system emits type info for every type that might need it at runtime (used by typeof<T>, typedefof<T>, and serialisation libraries). When a generic erased-union type is stored in a record field with a concrete type parameter (like Func: TypeA<string>), reflection tries to resolve the generic and fails.
Options
Option 1: Per-type [<NoReflection>] attribute
This would be a new attribute in Fable.Core that suppresses reflection emission for the decorated type. The main places to change:
src/Fable.Transforms/Transforms.Util.fs — in getEntityInfoHelper (or wherever type info is generated), check for the attribute and return a simpler/empty info
src/Fable.Transforms/Replacements.Util.fs — in typeInfo and related helpers, skip reflection for types with the attribute
This is feasible but touches Fable.Core (distributed on NuGet) and shared transform code. It would need careful design: if reflection is disabled for TypeA<'T>, what happens when code calls typeof<TypeA<string>>? It should either return a dummy type or raise a compile-time warning.
Option 2: Use --noReflection with selective opt-in
The existing --noReflection flag disables reflection globally. A --noReflection global flag combined with a [<EnableReflection>] attribute to opt specific types back in would be the inverse approach. This might be simpler since the default path (no reflection) is already implemented.
Option 3: Use a type wrapper without generics for the field
As you noted, anonymous records work around this. Another pattern is to wrap in a non-generic interface:
This loses type safety but avoids the generic reflection issue.
Recommendation
Option 1 seems most user-friendly. The implementation should:
Accept the attribute on type declarations
When the type has [<NoReflection>], emit a placeholder type info (e.g., { fullname: "...", generics: () => [] }) or no type info at all
Issue a compile-time warning if typeof<T> is used on such a type
This is a good candidate for a focused PR in Fable.Core and Replacements.Util.fs. If you'd like to pursue it, the key entry point to look at is typeInfo in src/Fable.Transforms/Replacements.Util.fs and the attribute check pattern already used for [<Erase>] types.
Note
🔒 Integrity filter blocked 43 items
The following items were blocked because they don't meet the GitHub integrity level.
Activity
MangelMaxime commentedon Oct 23, 2025
Note, in my situation I
Updateshave additional properties who are mark asmutablewhich is invalid for anonymous recordsgithub-actions commentedon Apr 5, 2026
🤖 This is an automated response from Repo Assist.
Here's a technical analysis of the options for this request.
Current behaviour
Fable's reflection system emits type info for every type that might need it at runtime (used by
typeof<T>,typedefof<T>, and serialisation libraries). When a generic erased-union type is stored in a record field with a concrete type parameter (likeFunc: TypeA<string>), reflection tries to resolve the generic and fails.Options
Option 1: Per-type
[<NoReflection>]attributeThis would be a new attribute in
Fable.Corethat suppresses reflection emission for the decorated type. The main places to change:src/Fable.Core/Fable.Core.fs— add[<AttributeUsage(AttributeTargets.Class ||| AttributeTargets.Struct)>] NoReflectionAttributesrc/Fable.Transforms/Transforms.Util.fs— ingetEntityInfoHelper(or wherever type info is generated), check for the attribute and return a simpler/empty infosrc/Fable.Transforms/Replacements.Util.fs— intypeInfoand related helpers, skip reflection for types with the attributeThis is feasible but touches
Fable.Core(distributed on NuGet) and shared transform code. It would need careful design: if reflection is disabled forTypeA<'T>, what happens when code callstypeof<TypeA<string>>? It should either return a dummy type or raise a compile-time warning.Option 2: Use
--noReflectionwith selective opt-inThe existing
--noReflectionflag disables reflection globally. A--noReflectionglobal flag combined with a[<EnableReflection>]attribute to opt specific types back in would be the inverse approach. This might be simpler since the default path (no reflection) is already implemented.Option 3: Use a type wrapper without generics for the field
As you noted, anonymous records work around this. Another pattern is to wrap in a non-generic interface:
This loses type safety but avoids the generic reflection issue.
Recommendation
Option 1 seems most user-friendly. The implementation should:
[<NoReflection>], emit a placeholder type info (e.g.,{ fullname: "...", generics: () => [] }) or no type info at alltypeof<T>is used on such a typeThis is a good candidate for a focused PR in
Fable.CoreandReplacements.Util.fs. If you'd like to pursue it, the key entry point to look at istypeInfoinsrc/Fable.Transforms/Replacements.Util.fsand the attribute check pattern already used for[<Erase>]types.Note
🔒 Integrity filter blocked 43 items
The following items were blocked because they don't meet the GitHub integrity level.
list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".import {type int32 } from ...syntax #4225list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".JSX.creatematch cases in children parsed as function call #4224list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".To allow these resources, lower
min-integrityin your GitHub frontmatter: