Closed Voronar closed 5 years ago
Hmm, the problem here is that F# doesn't have ad-hoc polymorphism. Sometimes it's possible to emulate it using inline functions and SRTP, but here you need access both to the member and the constructor so the syntax can become very cumbersome (not sure if it's even possible).
If you don't mind using interfaces, you can achieve a similar effect with flexible types:
type IAddClass<'T> =
abstract AddClass: string -> 'T
type DivComponentProps =
{ value: string; ClassName: string }
interface IAddClass<DivComponentProps> with
member this.AddClass c = { this with ClassName = this.ClassName + " " + c }
type SpanComponentProps =
{ text: string; ClassName: string }
interface IAddClass<SpanComponentProps> with
member this.AddClass c = { this with ClassName = this.ClassName + " " + c }
let enhance comp (props: #IAddClass<'props>) =
React.ofFunction comp (props.AddClass "red")
let SpanComponent (props: SpanComponentProps) =
React.span [
ClassName props.ClassName
] [ React.str props.text ]
let DivComponent (props: DivComponentProps) =
React.div [
ClassName props.ClassName
] [ React.str props.value ]
let EnhancedDiv = enhance DivComponent
let EnhancedSpan = enhance SpanComponent
That is to say what I can't make generic implementation of this code piece:
member this.AddClass c = { this with ClassName = this.ClassName + " " + c }
and I must duplicate the implementation for all types, that implements interface IAddClass
?
Hmm, not that I can think of. Maybe there is a way using something like FSharpPlus but I'm not sure. AFAIK there's no way to make record constructors generic. If you prefer not to use interfaces, I think the common way is to pass the transform in a parameter (as with a functor):
type DivComponentProps =
{ value: string; ClassName: string }
type SpanComponentProps =
{ text: string; ClassName: string }
let enhance comp (addClass: 'props->string->'props) (props: 'props) =
React.ofFunction comp (addClass props "red")
let SpanComponent (props: SpanComponentProps) =
React.span [
ClassName props.ClassName
] [ React.str props.text ]
let DivComponent (props: DivComponentProps) =
React.div [
ClassName props.ClassName
] [ React.str props.value ]
let EnhancedDiv = enhance DivComponent (fun p c ->
{ p with ClassName = p.ClassName + " " + c })
let EnhancedSpan = enhance SpanComponent (fun p c ->
{ p with ClassName = p.ClassName + " " + c })
According to this declined (by @dsyme) suggestion and my speculations about the subject I think a truly React HOC via record props is impossible even in a future.
I am trying to do the custom HOC. There is the code:
How to make the general
enhance
function instead ofenhanceDiv
andenhanceSpan
ones?P.S Playground for testing current code.