들어가며,
react-responsive 라이브러리를 사용해 반응형 웹을 만들며 여러가지 테스트를 해봤다.
타입스크립트를 사용했기 때문에 타입 지정을 해줘야 했다. 타입을 지정하는 방법 중에 interface와 type이 있는데 두 가지의 정확한 차이점을 알고 정리해놓으려고 한다.
본론
function Pc({ children }) {
const isPc = useMediaQuery({
query: '(min-width: 768px)',
});
return <div>{isPc && children}</div>;
}
react-responsive 라이브러리 내 useMediaQuery를 사용했다.
PC 버전과 Mobile 버전일 때를 나눠 만드려고 했으며, children을 통해 값을 받아오도록 코드를 짰다.
return <div>{isPc && children}</div>;
이 코드는 조건부 렌더링을 수행하는 부분이며, 'isPc'는 useMediaQuery 훅에서 받아오는 값이고 현재 화면이 특정 크기 이상인지 여부를 나타내는 값이다.
자바스크립트의 논리 연산자(AND, &&)를 사용해 isPC가 true일 때만 children을 렌더링한다.
즉, isPc가 true일 때만 <div>{children}</div>를 렌더링하고 그렇지 않으면 'null'을 렌더링한다.
결과적으로 isPc 값에 따라 해당하는 화면 크기에 맞는 내용리 렌더링된다. 반응형 웹 디자인에서 흔히 사용되는 패턴 중 하나이다!
이어서, children의 타입을 지정해줘야 하는데 그렇다면 어떻게 해주는게 좋을까?
import { ReactNode } from 'react';
interface PcProps {
children: ReactNode;
}
function Pc({ children }: PcProps) {
const isPc = useMediaQuery({
query: '(min-width: 768px)',
});
return <div>{isPc && children}</div>;
}
'ReactNode'을 사용해 모든 종류의 자식 요소를 허용하도록 했다.
여기서 'ReactNode'는 모든 종류의 자식을 나타내는 타입이며, 특정 타입의 자식만을 허용하려면 'ReactElement'를 사용할 수도 있다.
대부분의 경우 'ReactNode'을 사용해 모든 종류의 타입을 허용하는 것이 유연성이 높다.
그렇다면 꼭 interface로만 사용해야할까?
= 그렇지 않다! type으로 사용해도 된다.
import { ReactNode } from 'react';
type PcProps = {
children: ReactNode;
};
function Pc({ children }: PcProps) {
const isPc = useMediaQuery({
query: '(min-width: 768px)',
});
return <div>{isPc && children}</div>;
}
타입스크립트에서 타입을 선언하는 방법 중 1. interface 뿐만 아니라, 2. type도 사용할 수 있다.
두 가지 접근 방법은 유사하지만 일부 차이점이 있다.
interface와 type의 차이점을 알아보자.
1. 상속 가능 여부
- interface는 선언 병합이 가능하므로 같은 이름의 interface를 여러 곳에서 선언하면 자동으로 합쳐진다.
- type은 선언 병합이 불가능하며, 같은 이름의 type을 여러 곳에서 선언하면 오류가 발생한다.
2. 확장 가능성
- interface는 extends 라는 키워드를 사용해 확장이 가능하다.
- type은 extends 키워드를 사용해 확장할 수 있지만 '&' 연산자로도 가능하다.
3. 팀 내 스타일
- 팀의 스타일과 개발자 개인의 취향에따라 다르다. 어떤 것을 선택할지는 프로젝트의 요구사항, 개발자 팀의 선호도에 따라 달라진다.
여기서, 선언 병합(Declaration Merging)은 무엇일까?
타입스크립트 여러 곳에서 동일한 이름으로 선언된 인터페이스를 자동으로 합치는 기능이다.
코드의 가독성과 모듈성을 높여주는데 용이하다.
// 첫 번째 파일
interface Person {
name: string;
}
// 두 번째 파일
interface Person {
age: number;
}
// TypeScript는 자동으로 합쳐진다.
// 실제로는 아래처럼 동작한다.
// interface Person {
// name: string;
// age: number;
// }
const person: Person = {
name: 'John',
age: 30,
};
하지만, 타입은 충돌한다!
// 첫 번째 파일
type Car = {
brand: string;
};
// 두 번째 파일
type Car = {
model: string;
};
// TypeScript에서는 오류 발생
// "Cannot redeclare block-scoped variable 'Car'."
두 가지의 차이를 알고 적절하게 잘 사용해주면 될 것 같다.
추가적으로, interface와 type의 extends 를 사용할 때의 차이점이 궁금했다.
방식은 유사하지만 미묘한 차이가 있다.
// type 사용
type Animal = {
name: string;
age: number;
};
type Dog = Animal & {
breed: string;
};
// interface 사용
interface Animal {
name: string;
age: number;
}
interface Dog extends Animal {
breed: string;
}
1. 추가 속성 선언 방법
- type 에서는 & 연산자를 사용해 속성을 추가하거나 결합한다.
- interface 에서는 extends 키워드를 사용해 상속하는 방식으로 속성을 추가한다.
2. 문법적 차이
- type은 보다 일반적인 문법을 가지며 객체 뿐만 아니라 유니온 타입, 인터섹션 타입 등 다양한 형태의 타입을 정의할 수 있다.
- interface는 주로 객체 형태를 정의하며 상속과 메서드 선언 등 특별한 기능을 제공한다.
더 나아가 interface의 특별한 기능을 알아보자.
1. 상속
- interface는 다른 interface로부터 상속을 받을 수 있으며 코드의 재사용성을 높인다.
interface Shape {
color: string;
}
interface Square extends Shape {
sideLength: number;
}
const square: Square = {
color: 'red',
sideLength: 10,
};
Square 인터페이스는 Shape 인터페이스를 상속한다. 따라서 color 속성을 상속받아 사용할 수 있다.
2. 메서드 선언
- interface 안에서 메서드를 선언할 수 있다. 객체가 특정한 메서드를 구현해야 함을 나타낸다.
interface Printer {
print(): void;
}
class ConsolePrinter implements Printer {
print() {
console.log('Printing...');
}
}
Printer 인터페이스는 print 메서드를 선언하고 있다. 그리고 ConsolePrinter 클래스는 이 인터페이스를 구현하고 있어 print 메서드를 반드시 구현해야 한다.
3. 익명 인터페이스
- interface는 이름을 가지지 않은 익명 인터페이스로도 사용될 수 있다.
let rectangle: {
width: number;
height: number;
} = {
width: 10,
height: 20,
};
위의 예시에서 rectangle 변수의 타입을 익명 인터페이스로 지정하고 있다.
이러한 특별한 기능들은 interface를 사용해 코드를 더 명확하고 유연하게 작성하도록 도와준다.
마무리
타입스크립트를 다시 해보면서 타입지정을 할 때 interface와 type의 차이점을 어느정도 알 수 있었다.
타입을 지정하는게 처음엔 좀 어려웠는데 하다보니까 조금씩은 늘고 있는 것 같다.
까먹지 않게 지식들을 정리해놓으니 한 번 더 생각하게 되고 머릿속에서도 잘 정리가 된 것 같다.
'개발' 카테고리의 다른 글
[React] 리액트에서 FormData 다루기! (FormData를 이용해서 파일과 텍스트 post 요청하기) (0) | 2024.02.16 |
---|---|
[React/CRA] CRA + typescript + Eslint + prettier 초기 세팅하기 (1) | 2024.01.23 |
[성능 최적화] 웹 성능 최적화에 대한 고찰과 최적화 하는 방법을 알아보자 (3) | 2024.01.18 |
[자료구조] 해시 (Hash, Hash Table, Hash Function)와 자바스크립트에서의 해시맵 (4) | 2024.01.07 |
[자료구조] 이분 탐색/이진 탐색 (Binary Search) (1) | 2024.01.04 |