Mojang / ore-ui

💎 Building blocks to construct game UIs using web tech.
https://react-facet.mojang.com/
MIT License
409 stars 18 forks source link

Introduce With component #28

Closed xaviervia closed 2 years ago

xaviervia commented 2 years ago

Example:

type UserDataProps = {
  name: FacetProp<string>
  middlename?: FacetProp<string | undefined>
}

const UserData = ({ name, middlename }: UserDataProps) => {
  const nameFacet = useFacetWrap(name)
  const middlenameFacet = useFacetWrap(middlename)

  return (
    <div>
      <p>Name: <fast-text text={nameFacet} /></p>
      <With data={middlenameFacet}>
        {(middlename) => <p>Middlename: <fast-text text={middlename} /></p>}
      </With>
    </div>
  )
}

Why?

The current component that supports a similar use case, Mount, has the defect that TypeScript is not able to tell when the data used inside it is defined. It cannot use the when clause to refine the type. In particular, the following code will lead to an annoying type error (since you as a developer know the code is correct, but TypeScript doesn't)

type UserDataProps = {
  name: FacetProp<string>
  middlename?: FacetProp<string | undefined>
}

const UserData = ({ name, middlename }: UserDataProps) => {
  const nameFacet = useFacetWrap(name)
  const middlenameFacet = useFacetWrap(middlename)

  return (
    <div>
      <p>Name: <fast-text text={nameFacet} /></p>
      <Mount data={useFacetMap((middlename) => middlename != null, [],[middlenameFacet])}>
        <p>Middlename: <fast-text text={middlenameFacet} /></p> 
        {/* Since TypeScript cannot know that `middlenameFacet` now holds a `string` for sure and still thinks that
            it could be `string | undefined`, it will complain. The only way to fix this is to extract a new component
            or with a type assertion. Neither is good */}
      </With>
    </div>
  )
}

TODO