Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
154 views
in Technique[技术] by (71.8m points)

javascript - Flow: cant create react component that takes a generic or an object

I am struggling to understand why flow doesn't want me to pase a concrete object type to a react component that may take a generic or ay object of one specific shape. It complaints that the existing properties on the concrete object are missing on the expected object. But the type I'm passing it is meant to be inferred as the generic one. I think the problem is that I'm passing an array of one type, while it expects an array of two possible types (even if I don't want to use the second type) Here is a small reproduction:

import React, { useState, useEffect } from 'react'

const data: {mola: boolean}[] = [{mola: true}]

type Props<T:{}> = {
a: Array<T|{cool: boolean}>
}

const Test = <T:{}>({a}:Props<T>) => 
    <div>
       {a.map(
           (props) => props.cool ?'cool' : 'other'
        )}
    </div>

const w = () => { return <Test a={data||[{mola: false}]} /> }

This is the error flow gives me:

11: const w = () => { return <Test a={data||[{mola: false}]} /> }
                                      ^ Cannot create `Test` element because property `mola` 
is missing in object type [1] but exists in object type [2] in array element of property `a`. [prop-missing]

References:
6: a:  Array<T|{cool: boolean}>
               ^ [1]
3: const data: {mola: boolean}[] = [{mola: true}]
               ^ [2]

And a Try flow repl

EDIT: I added a bit more complex example to make more obvious how I want to use the type

question from:https://stackoverflow.com/questions/66066384/flow-cant-create-react-component-that-takes-a-generic-or-an-object

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The problem Flow is trying to prevent me from is very well explained on this stackoverflow question

Declaring that the lower component can take an array of a sum type enables that component to push values that fulfill one or the other, like this:

const Test = <T:{}>({a}:Props<T>) => {
    a.push({ cool: true })

    return (
    <div>
       {a.map(
           (props) => props.cool ?'cool' : 'other'
        )}
    </div>)
}

Inside the component it is not violating the type, because it is a sum type and it matches one of the types. However, the array that I'm passing down is of one type exclusively. Because of this, flow will not allow you tu pass down such array because there is the risk that it gets "perverted" inside the component.

However, if you declare the array as readOnly, you are guaranteed that nobody will push anything to your precious array, and then you can pass it down.

type Props<T:{}> = {
a: $ReadOnlyArray<T|{ +cool: boolean }>,
}

Fixed example


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...