ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Typescript] React에서 props 전달할때 조건을 걸 수 있는 Trick!
    front-end/Javascript&Typescript 2023. 7. 31. 21:42

    Passing props conditional

     

    리액트 + 타입스크립트를 통해 개발을 하다보면 , 부모 컴포넌트에서 하위 컴포넌트로 props를 전달 할때 하위 컴포넌트에서 interface나 type 을 이용하여 , 전달받는 props 의 타입을 정의 해주는데요!

    만약에 전달 받는 props를 조건을 걸어서 전달하려면 어떻게 해야 할까요?

     

    아래의 밈을 보면 여성에겐 나이를 묻지말고 , 남자의 경우는 월급을 묻지 마라라는 밈 입니다.

    props 전달을 아래의 조건이라면 어떻게 구현해야할까요?

    즉 gender가 male 일 경우 age props를 받고 , 반대로 gender가 female 일 경우 salary의 props를 받는것입니다.

     

    다시한번 조건에대해 설명하자면 ,  남자 일 경우 월급을 물어보는게 실례 이므로 나이를 props로 받아오고 , 여자인 경우 나이를 물어보는게 실례이므로 props로 월급을 받아오는 것 입니다.

     

     

    우선 부모 컴포넌트에서 name , gender , age , salary 총 네가지 props를 전달 받습니다.gender 은 male 과 female 의 유니온 타입을 받고 있습니다.

     

     

    App.tsx (Parent Component)

    import Child from "./Child";
    
    export default function App(){
      return <Child name="John" gender="male"/>
    }

     

    Child.tsx

    interface ChildProps {
      name: string;
      gender: "male" | "female";
      salary?: number;
      age?: number;
    }
    
    export default function Child({ name, gender, salary, age }: ChildProps) {
      return <div>Child</div>;
    }

     

    위의 코드라면 salary 와 age가 optional 이라서 props로 전달을 안받아도 에러가 없이 잘 나올겁니다.

    근데 제가 원하는것은 optianl로 props를 전달 받는게 아니라, gender이 male 일 경우엔 age props를 받아오고 , female일 경우는 salary props 를 받아오는거인데요

    Child 컴포넌트의 interface 를 아래 처럼 수정 해보겠습니다!


    Type version

    type ChildProps = {
      name: string;
    } & ({
      gender:"male";
      age:number;
    } | {
      gender:"female";
      salary:number
    });
    
    
    export default function Child({ name }: ChildProps) {
      return <div>Child</div>;
    }

    우선 interface 가 type으로 바뀌었는데요 (아래 interface로 하는 방법 있으니 참고해주세요).

    interface 가 type으로 바뀐것이 중요한게 아니라 , name의 props를 필수로 받아오고 gender의 타입이 male이면 age를 받아오고 ,

    female 이면 salary props를 받아 오는 것입니다.

     

    아래 코드를 보면 male 이면  age props를 , female이면 salary props를 받아와서 typescript의 자동완성 기능이 발휘합니다 

     

    만약 gender가 male일때 age가 아닌 salary props를 전달하거나 female 일때 age props를 전달하려고 하면 아래와 같은 타입 에러가

    발생 합니다!

     

    위의 타입코드를 아래의 코드처럼 MaleProps 와 FemaleProps 로 나눠서 깔끔하게 수정해서 사용할 수 있습니다.

    type ChildProps = {
      name: string;
    } & (
      MaleProps | FemaleProps
    )
    
    type MaleProps = {
      gender:'male';
      age:number;
    }
    
    type FemaleProps = {
      gender:'female';
      salary: number;
    }
    
    
    export default function Child({ name , gender }: ChildProps) {
      return <div>Child</div>;
    }

    하지만 여기서 Child 컴포넌트에 props에 salary 나 age값을 넣으면 ChildProps의 salary 나 age 타입이 없다고 에러가 발생합니다.

    type ChildProps = {
      name: string;
    } & (
      MaleProps | FemaleProps
    )
    
    type MaleProps = {
      gender:'male';
      age:number;
    }
    
    type FemaleProps = {
      gender:'female';
      salary: number;
    }
    
    
    export default function Child({ name , gender , age , salary}: ChildProps) //Error! {
      return <div>Child</div>;
    }

     

     

    위에서 진행 한거처럼 salary나 age의 props는 그냥 받는게 아니라 gender의 조건에 따라 props를 전달 받고 있습니다.

    아래 코드처럼 props를 구조분해 할당으로 받지말고 props로 전달을 받아서 props.gender === 'female' 또는 props.gender === 'male' 로 접근을 하면 타입스크립트의 아름다운 자동완성 기능을 또 확인 할 수 있습니다!

    gender 가 female 일 경우는 salary 의 props로 , male 일 경우 age의 props를 이용 할 수 있습니다.

     

    interface 로 컨디셔널 하게 props 받기

    interface Person {
        name: string;
    }
    interface Male extends Person {
        gender: "male",
        salary: number;
    }
    interface Female extends Person {
        gender: "female";
        weight: number;
    }
    
    type Props = Male | Female;

     


    뽀나스_More usage case

    type ApiResponse<T> =
      | { status: 'success'; data: T; timeStamp: Date }
      | { status: 'error'; message: string; timeStamp: Date };
    
    let response1: ApiResponse<number> = {
      status:'success',
      data:200,
      timeStamp:new Date()
    }
    
    let response2: ApiResponse<number> = {
      status:'error',
      message:'There is an error!',
      timeStamp:new Date()
    }

    API의 response 를 예제로 들어 type을 만들어보았는데요.


    ApiResponse<T>는 두 가지 유형의 객체로 구성됩니다

    성공 상태를 나타내는 객체: status가 'success'이며, 성공한 경우에는 data와 timeStamp 속성을 포함합니다.
    data 속성은 T 타입의 데이터를 담고 있으며, timeStamp 속성은 응답이 생성된 시간을 나타냅니다.

    에러 상태를 나타내는 객체: status가 'error'이며, 에러가 발생한 경우에는 message와 timeStamp 속성을 포함합니다. message 속성은 발생한 에러에 대한 설명을 담고 있습니다


    response1은 status 가 'success' 로 data의 값에 접근 할 수 있고 , response2는 status가 'error'니까 message의 접근 할 수있습니다.


     

    Reference

    https://www.youtube.com/watch?v=9i38FPugxB8 

     

Designed by Tistory.