2
respostas

[React TypeScript] como tornar um tipo obrigatório, quando um tipo opcional for preenchido

Dado o seguinte tipo

interface TypeA {
    a?: string
    b?: string
    c?: string
}

export const Component = ({  } as TypeA) => <></>

Eu posso utilizar opcionalmente ou o valor A ou B ou C , porem se eu utilizo o valor A obrigatoriamente preciso preencher o valor C por exemplo

<Component 
    b={ 'string' }
/>
<Component 
    a={ 'string' }
    c={ 'string' }
/>
<Component 
    c={ 'string' }
/>

se eu preencher os valores independentes b ou c nao me acusa erro, porem preenchendo A ele me obriga a preencher C,

é possível fazer uma tipagem dinâmica dessa forma?

2 respostas

Boa tarde Felix, tudo certo?

Primeiramente gostaria de parabenizá-lo pela forma como você organizou sua dúvida. Você trouxe um exemplo muito claro do que gostaria de fazer e ilustrou muito bem a tarefa com o código. Se me permite, futuramente eu sugiro deixar mais claro que algumas afirmações são hipotéticas, como a que vem logo após o segundo bloco de código, e também citar qual que é a aplicação real que você vai utilizar essa funcionalidade, pois existem algumas soluções "fora da caixa" que podemos deixar passar ao não falar sobre um cenário mais geral da base de códigos.

Dito isso, eu pensei com o time aqui 2 métodos que podem te auxiliar:

O primeiro seriam os decorators, que te permitem modificar o código para interfaces diferentes. Você pode aprender mais sobre eles no curso 3 de TypeScript.

A outra forma, fugindo um pouco da sua proposta do TypeScript, seria utilizar um operador ternário no React e apenas mostrar o componente caso, por exemplo, os valores a e c estejam definidos.

Espero ter ajudado. Continue assim e bons estudos!

Boa tarde Joao, tudo tranquilo meu querido, e contigo?

Obrigado pelo feedback, então o contexto da minha aplicação seria no seguinte código:

import { FormEvent, Fragment, useEffect, useState } from "react"
import { Colors } from "../../colors"
import { DefaultValues, TypeSetState } from "../../types"
import { CheckInput } from "./check"
import { ComboInput } from "./combo"
import { TextInput } from "./text"
import { LabelCustom } from "./text/style"

export enum TypesFormInput {
  TEXT = 'TEXT',
  COMBO = 'COMBO',
  CHECK = 'CHECK' 
}

export type OptionsSelect = Array<{ value: any, label: string }>

export interface PropsFormInput extends DefaultValues {
  type: TypesFormInput
  color?: string
  title?: string
  options?: OptionsSelect
  onChange?: (event: FormEvent<HTMLInputElement>, setState: TypeSetState<StateFormInput>) => void
}

export interface StateFormInput {
  color: string
  error: boolean
  value: string | null
}

export const FormInput = (props: PropsFormInput) => {
  const [ state, setState ] = useState({  } as StateFormInput)

  useEffect(() => {
    setState(prevState => ({ ...prevState, color: state.error ? 'red' : Colors.gray }))
  }, [ state.error ])

  const define = ():JSX.Element => {
    switch (props.type) {

      case TypesFormInput.TEXT:
        return (
          <TextInput 
            { ...props } 
            { ...state } 
            color={ state.color }
            onChange={ (event: FormEvent<HTMLInputElement>) => props.onChange?.(event, setState) } 
          />
        )

      case TypesFormInput.COMBO:
        return (
          <ComboInput 
            options={ props.options || [] } 
            { ...props }
          />
        )

      case TypesFormInput.CHECK:
        return <CheckInput { ...props }/>

      default: 
        return <></>
    }
  }

  return (
    <Fragment>
      <LabelCustom>
        { props.title }
        { define() }
      </LabelCustom>
    </Fragment>
  )
}

Gostaria de obrigar o programador a quando declarar a props "onChange" que forneça também a "value", embora atualmente esteja funcionando, achei meio gamb a forma que utilizei, outra questão seria validar qual o tipo de formInput foi utilizado, se o pragramador escolheu o input "COMBO" obriga-lo a preencher as "options" isso em tempo de desenvolvimento e evitar tratativas como :

props.options || []

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software