TypeScript

유관희·2022년 11월 1일
0

→ Open in Slid


interface StarsProps {  // prop 타입 정의
	star: number;
}

type StarsProps = {
  star:number;
}
// type으로 표현 했을 때..

const Stars: React.FC<StarsProps> = ({ star }) => {   // 2
	// 로직 변수 Stars 는 인자를 star로 받는데 이 스타일은
  // starsProps 형식이다.

	return ( 
		<div>
			{makeStars(star)}
		</div>
	)
}

import React from "react";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Stars star={3} />
    </div>
  );
}

//////////////////////////////////

interface StarProps {
  star: number;
}

const Stars: React.FC<StarProps> = ({ star }) => {
  return <div>star : {star}</div>;
};
// React.FC => return 값이  JSX 형식이라는 것을 알려줌
// 객체인 star 모양은 StarProps 모양일거라는 것을 알려줌

Stars 컴포넌트에 return 타입은 따로 명시하지 않았는데 React.FC 타입에서 함수의 매개변수인 props와 반환값인 JSX가 이미 정의되어있기 때문입니다.

‏‏‎ ‎

// 리액트의 FC 타입 분석하기
// node_modules폴더 하위에 "@types/react/index.d.ts"경로

type FC<P = {}> = FunctionComponent<P>;  // 1
// P라는 type을 받을텐데  아무것도 없다면 빈객체로 돌려줘라
interface FunctionComponent<P = {}> {  // 2
	(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;  // 3
	propTypes?: WeakValidationMap<P>;
	contextTypes?: ValidationMap<any>;
	defaultProps?: Partial<P>;
	displayName?: string;
}
  1. FunctionComponent라는 타입에 P를 제네릭으로 받은 것이 타입 FC입니다. FC타입을 사용할 때 제네릭을 넘기지 않으면 빈객체를 기본값으로 할당합니다

  2. FunctionComponent은 제네릭 P를 넘겨받는 interface 타입입니다. 총 5개의 프로퍼티를 갖고 있는데, 하나만 필수이고 물음표가 붙은 나머지 4개는 함수형 컴포넌트에 선택적으로 할당할 수 있습니다.

  3. 함수 타입 정의! props매개변수를 받아서 ReactElement 타입 or null을 반환합니다. PropsWithChildren과 ReactElement 타입도 분석해보세요!!

‏‏‎ ‎

2-2. 일반적인 함수정의 방식

‏‏‎ ‎

interface StarsProps {   // prop 타입 정의
	star: number;
}

const Stars = ({ star }: StarsProps): JSX.Element => {  // 1
	// 로직

	return ( 
		<div>
			{makeStars(star)}
		</div>
		)
}

<Stars star={star}/>
  Stars({star:star}) //컴포넌트 부르는 방

함수형 컴포넌트는 props를 매개변수로 받고 JSX를 return 해야 합니다. 그래서 매개변수 타입을 StarsProps로, 반환하는 타입을 JSX.Element로 직접 명시했습니다. (return 타입을 작성하지 않아도 타입추론이 되므로 JSX.Element는 생략할 수 있습니다)

‏‏‎ ‎

3. Hooks

3-1. useState

//특별한 타입 정의 없이

const [like, setLike] = useState(false);//<= 함수부르네?

//로직 생략
setLike(!like);

위와 같이 특별히 타입을 명시하지 않더라도 타입추론을 통하여 타입이 지정됩니다. like는 boolean 형이 되고, setLike 함수는 boolean 형만 인자로 받게 됩니다.

VSCode에서 useState 위에 마우스를 올려보면 추론된 타입을 확인할 수 있습니다.

‏‏‎ ‎

// 유니온 타입으로 전달
const [like, setLike] = useState<boolean | null>(null);

//생략
if (like) {
	// 좋아요 true 일 때만 실행할 로직
}

우리가 state의 초기값을 설정할 때 null을 자주 사용하기도 하죠. 그럴 때는 유니온 타입을 사용하여 타입을 명시해주면 됩니다.

‏‏‎ ‎

state에 객체가 포함된 경우에는 자세한 프로퍼티 타입을 알 수 있도록 아래와 같이 정의해주면 됩니다.

// state 타입 정의
interface Comment {
	comment: string;
	username: string;
	date: string;
	star: number;
}

//생략

const [comments, setComments] = useState<Comment[]>([]);

[
  {
    comment: 'hihi',
    username: 'yun',
    star:3,
  },
  {
    comment: 'hihi',
    username: 'yun',
    star:3,
  }
]

위의 코드는 comments 상태가 객체 배열인 경우로, 아래와 같이 생긴 데이터를 받아야할 때를 대비하여 정의한 것입니다.

// comments 데이터
[{
	comment: '넘 맛있어요..',
	username: 'kim',
	date: '2020.07.01',
	star: 4
}, {
	comment: '가성비 최고!',
	username: 'lee',
	date: '2020.07.20',
	star: 5
}]

‏‏‎ ‎

3-2. useRef

useRef 또한 useState처럼 타입을 명시하지 않아도 됩니다. 만약 코드의 명확성을 위해서 타입을 정의하고 싶은 경우 아래와 같이 ref의 태그에 맞는 제네릭을 넘겨주면 됩니다.

const reviewRef = useRef<HTMLDivElement>(null);  // 1
//로직 생략

return (
	<>
		<Review reviewTextRef={reviewRef} />  // 2
		<div ref={reviewRef}>  // 3
			리뷰
		</div>
	</>
)
  1. userRef우측에 HTMLDivElement타입을 제네릭으로 넘겨주었습니다. 3번 코드에서 div태그이기 때문에 div용 타입을 선택한 것입니다. HTMLDivElement말고도 여러 태그의 타입이 존재합니다. 예를 들어 HTMLAnchorElement, HTMLButtonElement, HTMLTableElement 등이 있습니다

  2. 정의된 reviewRef를 자식 컴포넌트에 props로 넘겨보았습니다

‏‏‎ ‎

4. Event Handler

이벤트 핸들러 함수의 이벤트 매개변수에는 특별한 타입이 필요합니다. 물론 매개변수에 타입을 명시하지 않아도 오류는 나지 않지만, 정확히 어떤 종류의 이벤트이고, 어느 태그에서 발생하는 것인지 써주는 것이 좋습니다.

// onCahnge 이벤트 예제
const updateValue = (e: React.ChangeEvent<HTMLInputElement>) => { // 1
	setEmail(e.target.value);
};

//생략

<input onChange={updateValue} />

updateValue 이벤트 핸들러는 "이벤트"를 매개변수로 받습니다. 이벤트 타입은 리액트에서 제공하는 타입을 사용하면 됩니다. 여기서는 change 이벤트 이므로 ChangeEvent 타입을 사용하였고, input태그에서 발생하므로 HTMLInputElement를 제네릭으로 넘겨주었습니다.

리액트에 click, change, scroll 등 여러가지 이벤트가 있는데 이벤트 타입은 리액트에서 제공하는 것으로 사용하면 됩니다. 일반적으로 타입 이름은 "이벤트타입Event"으로 ChangeEvent, FormEvent, TouchEvent, FocusEvent, KeyboardEvent, MouseEvent, DragEvent 등이 있습니다.

‏‏‎ ‎

5. 기타

5-1. JSX.Element

변수에 JSX를 할당해서 값처럼 사용하는 경우가 많습니다. 간단히 아래와 같이 선언할 수 있습니다.

const WarningText: JSX.Element = <p>다시 확인해주세요.</p>

‏‏‎ ‎

5-2. 전역 변수

window에 외부 라이브러리 변수를 추가하려면 아래와 같이 해당 라이브러리에서 사용하는 전역 변수명을 추가하면 됩니다.

declare global {
	interface Window {
		kakao: any;
	}
}

예를 들어 kakao 로그인을 위해서 라이브러리를 추가하는 경우 window.kakao로 접근하면 됩니다. 다만 타입스크립트 프로젝트에서는 window 객체에 추가된 외부라이브러리라 할지라도 사용하기 위해 타입을 정의하지 않으면 다음과 같은 에러메시지가 나옵니다.

Property 'kakao' does not exist on type 'Window & typeof globalThis'.

‏‏‎ ‎

예시.

console 창에서 array 의 객체를 복사한 후

const obj ={
    "id": "btc-bitcoin",
    "name": "Bitcoin",
    "symbol": "BTC",
    "rank": 1,
    "is_new": false,
    "is_active": true,
    "type": "coin"
} // 콘솔창에서 직접 변수를 만든다. 

Object.entries(obj).reduce((acc,[key,value])=>
  acc + `${key}:${typeof value} ||`,'')                        )

Object.entries(obj).reduce((acc,[key,value])=> acc + `key:{key}:{typeof value} ||`,'')

각 객체의 타입을 알아내는 방법이다.

//interface CoinType을 

const [coins, setCoins] = useState([]);
			// To
const [coins, setCoins] = useState<CoinType[]>([]);
// 이렇게 useState 뒤에 붙여주고 이게 객체이기 때문에 
// CoinType 뒤에 [] 붙여준다. 


//App 에서 props 로 Card 에게 넘겨 주었을때 
export interface CoinType{
  id:string 
  name:string 
  symbol:string 
  rank:number 
  is_new:boolean 
  is_active:boolean 
  type:string 
} // App 에 있는 interface에 export를 넣어 다른 곳에서도
// 부를 수 있게 한다.

import React from 'react';
import { CoinType } from '../App';
import './Card.scss';

const Card = (props:CoinType) => {}

// React.FC 사용시
const Card: React.FC<CoinType> = props =>{}



const Card = (props:CoinType) => {
  const { name, rank, symbol } = props;
}
// 만약 CoinType 전체가 필요 없고 name, rank, symbol 만 
// 필요할경우..

interface CardProps{
  name: string;
  rank: number;
  symbol: string;
}
// 필요한 것만 interface로 만든다음
const Card = (props: CardProps) =>{}

// 또 다른 방법으로는 Pick을 쓸수 있는데,
interface Todo{
  title: string;
  description: string;
  completed: boolean;
}
//위 interface에서 title,complted 만 쓰고 싶다면,
type TodoPreview = Pick<Todo,"title"|"completed">;

const todo: TodoPreview ={
  title: "Clean room",
  completed: false,
};

‏‏‎ ‎

profile
안녕하세요~

0개의 댓글