React

[React] Typescript 상속을 이용해 라이브러리에 없는 타입 지정 (React+ Typescript + Plotly js)

판교너굴맨 2021. 6. 16. 20:33
interface A {
    key: number;
    value: number;
    test1: number;
 }
 
 interface AA {
    key: number;
    value: number;
    test2: number;
 }

  const a: AA = {
    key: 1,
    value: 2,
    test2: 3
  };
  interface B extends AA {
    test1: number;
  }
  interface C{
    test3: number;
  }

  console.log((a as unknown as A).test1); // undifind (AA와 A는 연관된 관계가 아니다.)
  console.log((a as B).test1); // undifind (AA와 B는 연관된 관계이다.)
  console.log((a as B).test2); // 3
  console.log(a as unknown as C) // {key: 1, value: 2, test2: 3}
  
  /*
  자식-부모관계(연관된 관계)가 아니라면 as unknown을 먼저 정의해 주어야 한다. 
  */
  
  /* 
  타입 캐스팅을 해줌으로써 사용하는 요소가 정의되지 않았더라도 타입을 정의해 줄 수 있다.
  라이브러리를 사용하는데 사용하려는 속성이 type 정의가 안되어 있다면 
  타입 캐스팅을 통해 정의해 줄 수 있다. 
  
  쉽게 말해서 타입 캐스팅을 해주면 타입 내에 있는 요소만 검사하고,
  없는 요소는 검사하지 않고 지나간다고 이해했다.
  */

프로젝트에서 발생

  interface PieDatum extends PlotDatum {
    label: string;
  }
  interface PieEvent extends PlotMouseEvent {
    points: PieDatum[];
  }
  const onGetImpLabel = (e: PieEvent) => {
    console.log(e);
    dispatch(setImpLabel(e.points[0].label));
  };

return(
  <Plot
    data={[data] as Data[]}
      layout={layout}
      config={{ displayModeBar: false, responsive: false }}
      className={style.impChart}
      onClick={onGetImpLabel as (event: Readonly<PlotMouseEvent>) => void}
    />
)

원인

내가 필요한 부분은 point[0].label이었다.

points의 타입을 확인하면

PlotDatum 타입이 내가 사용하려는 point[0].label의 타입이다.
이런.. 확인해보니 내가 필요한 label 부분만 쏙 빠져 있었다!
(plotly를 사용하다 보면 history의 ybins, point의 label 빠져 있는 변수들이 간혹 보인다. )

 

해결

 interface PieEvent extends PlotMouseEvent {
    points: PieDatum[];
  }
  const onGetImpLabel = (e: PieEvent) => {
    console.log(e);
    dispatch(setImpLabel(e.points[0].label));
  };

페이지 맨 위의 예제와 비슷한 방법으로 해결했다.

label이 있어야 할 PlotDatum 타입을 상속 받아 자식 타입에 label 을 작성 해준다.

 interface PieDatum extends PlotDatum {
    label: string;
  }

마찬가지로 PlotMouseEvent 의 타입을 상속 받아 자식 타입인 PieEvent을 생성하고,
PlotDatum의 자식 타입인 PieDatum타입을 points의 타입으로 정의해 준다

interface PieEvent extends PlotMouseEvent {
    points: PieDatum[];
  }

이제 event 파라미터에 PieEvent 타입을 정의해주면 된다.

const onGetImpLabel = (e: PieEvent) => {
    dispatch(setImpLabel(e.points[0].label));
  };

자기 타입을 다시 타입 캐스팅 해줘야 하는 이유는?

위와 같이 했는데 onClick 이벤트에서 에러가 났다

onGetImpLabel함수에서 onClick event 파라미터의 타입과 다른 타입을 사용한 탓인 것 같다.

그래서 onClick이벤트의 기존 타입을 onGetImpLabel함수에 타입 캐스팅을 해준다.

onClick={onGetImpLabel as (event: Readonly<PlotMouseEvent>) => void}
//자식-부모관계(연관된 관계)이므로 unknown을 생략할 수 있다.

 

plotly.js-react 깃허브 이슈에 등록

 

There are no properties to use when using typeScript. · Issue #247 · plotly/react-plotly.js

When using histogram charts, there are xbins properties but no ybins properties. data={[ { type: 'histogram', text: chartText, histfunc: 'sum', x, y, ybins: { start: y[y.length - 6]...

github.com