타입스크립트의 Generic이란?
> 타입스크립트를 경험해보지는 못했지만, 자바의 제네릭은 알고 있다.
자바의 제네릭은 클래스나 메서드에서 사용할 데이터 타입을 나중에 지정할 수 있도록 해주는 기능(타입을 매개변수로 받는다고 생각)이다.
<T> T func(T val) 처럼 제네릭 타입(T)를 선언해서 어떤 타입이든 받아서 변환할 수 있다.
타입스크립트의 제네릭도 비슷한 개념인 것 같다.
어떤 타입이 올지 미리 정하지 않고 나중에 사용할 때 타입을 외부에서 지정할 수 있도록 해주는 기능이다.
이렇게 되면 코드를 재사용하면서도 타입 안정성을 보장해주는 이점이 있다.
예를 들어 any를 사용하는 함수는 어떤 타입이든 받을 수 있지만, 반환 타입이 정확하지 않아 타입 안정성이 떨어지게 된다.
identity(123)처럼 숫자를 넘겨도 반환값이 어떤 타입인지 알 수 없어서 문제가 생길 수가 있다.
function identity(value: any): any {
return value;
}
이걸 제네릭으로 바꾸면 이렇게 된다.
function identity<T>(value: T): T {
return value;
}
identity 함수는 제네릭 타입을 받아들이고(T)
매개변수 value와 반환값은 모두 같은 T 타입이 된다.
그리고 T는 함수 호출 시점에 결정되기 때문에 받은 값을 그대로 반환하고 타입이 유지된다.
identity<number>(123); // T는 number로 추론
identity<string>('hi'); // T는 string으로 추론
react 컴포넌트에서 사용하게 된다면
api 요청을 했을 때 응답 형식을 제네릭을 통해 유연 + 타입안정성을 확보하게 표현할 수 있다.
interface ApiResponse<T> {
status: number;
message: string;
data: T;
}
T가 string이므로 data는 문자열이 된다.
const response1: ApiResponse<string> = {
status: 200,
message: '요청 성공',
data: '회원가입 완료',
};
data가 객체일 때
interface User {
id: number;
name: string;
}
const response2: ApiResponse<User> = {
status: 200,
message: '유저 조회 성공',
data: {
id: 1,
name: '홍길동',
},
};
data가 배열일 때
const response3: ApiResponse<User[]> = {
status: 200,
message: '유저 목록 조회 성공',
data: [
{ id: 1, name: '홍길동' },
{ id: 2, name: '김철수' },
],
};
이렇게 사용할 수 있다.
매번 ApiResponseUser, ApiResponseProduct 등으로 별도 타입을 만들면 코드 중복이 많아지기 때문에
data 부분만 바뀌고 나머지 구조는 항상 동일하므로 제네릭으로 일반화하고
타입스크립트가 T의 실제 타입을 추론해서 타입 안정성을 확보할 수 있다.
npm 패키지 배포
교육기관에서 진행한 프로젝트 단계에서는 기존의 npm 패키지를 활용하는 수준에 머물렀다.
하지만 이 질문을 받고 나서 궁금하기도 하고 한번 어떤 방식으로 배포할 수 있을까? 라는 생각에 실제로 npm 패키지를 직접 만들어서 배포할 수 있는 방법을 찾아봤고,
기본적인 설정 방법, TypeScript 기반의 패키지 작성, 그리고 'npm publish' 과정을 학습해보았다.
간단한 개인정보 블러 기능을 넣은 패키지를 만들어서 배포해봤다.
index.js
/**
* 문자열의 가운데를 *로 마스킹합니다.
* 이름, 전화번호 등 민감 정보에 유용합니다.
* @param {string} str - 원본 문자열
* @param {number} visibleFront - 앞에 보여줄 글자 수
* @param {number} visibleBack - 뒤에 보여줄 글자 수
* @returns {string} - 마스킹된 문자열
*/
function blurText(str, visibleFront = 1, visibleBack = 1) {
const totalLength = str.length;
// 전체 길이가 2 이하일 경우: 앞 한 글자만 보여주고 나머지는 *
if (totalLength <= 2) {
return str[0] + '*';
}
// 전체 길이가 보여줄 앞/뒤 글자 수보다 작아도 최소 1개씩 보여주고 나머지 마스킹
const front = Math.min(visibleFront, totalLength - 1);
const back = Math.min(visibleBack, totalLength - front - 1);
const maskedLength = totalLength - (front + back);
const stars = '*'.repeat(maskedLength);
return str.slice(0, front) + stars + str.slice(totalLength - back);
}
module.exports = {
blurText,
};
test.js
const { blurText } = require('./index');
console.log(blurText("홍길동")); // 홍*동
console.log(blurText("이")); // 이*
console.log(blurText("김")); // 김*
console.log(blurText("01012345678")); // 01****5678
console.log(blurText("abcdefg", 1, 2)); // a***fg
npm install
npm install ys2text
사용 예시
function StoreInfo({ ownerName }) {
return (
<div>
<p>사장님 이름: {blurText(ownerName)}</p>
</div>
);
}
https://www.npmjs.com/package/ys2text
react 의 Context API와 Zustand 라이브러리를 분석하고 렌더링 최적화 관점에서 비교하기
Context API는 React의 내장 기능으로 보통 전역 상태를 공유하는 목적으로 많이 사용한다.
Context API를 사용하게 되면 단계마다 일일이 props를 넘겨주지 않아도 트리 전체에 데이터를 제공할 수 있게 된다.
렌더링 최적화 관점에서 보게 되면
상태 변경 시 Provider 아래 모든 컴포넌트가 리렌더링 되고 심지어 변경된 값을 사용하지 않는 컴포넌트도 리렌더링 된다.
useContext는 전역 상태를 참조할 뿐이고, 상태가 바뀌면 관련된 모든 자식 컴포넌트가 다시 렌더링된다.
또 최적화를 위해 useContext + React.memo + useCallback 등 수동 최적화 필요하다.
또한 Context를 여러 개 만들어야 관리가 가능하고 상태가 커질수록 리렌더링에 대한 부담이 늘어난다.
Zustand는 상태라는 뜻을 가진 독일어인데,
단순화된 Flux 원리를 사용하며 작고 빠르고 확장 가능한 상태 관리 솔루션이다. Hooks에 기반해 편리한 API를 제공하기도 한다.
상태 변경 시 구독한 상태만 리렌더링 되며, 사용하지 않는 컴포넌트는 리렌더링이 되지 않는다.또한 Zustand는 내부적으로 개별 selector 단위로 구독하고, 필요한 컴포넌트만 리렌더링 하게 된다.상태 분리시에도 store 내부에서 상태를 논리적으로 나누기 쉽다.Context API에서는 selector 부분을 직접 구현해야 하지만, Zustand는 기본으로 지원된다. (useStore(state => state.value))
결과적으로 Zustand는 상태 전체를 구독하는 것이 아니라 필요한 필드만 골라서 구독할 수 있기 때문에 리렌더링 범위가 자동으로 축소가 된다.
또 얕은 비교인 Shallow comparison가 기본으로 적용되어있기 때문에 자연스럽게 리렌더링 최적화 효과를 누릴 수 있게 해준다.
서류 통과 후 분석전형에 대한 문제들을 공부해 보았다.
새로 배워야 하는 부분들은 끝이 없는 것 같다. 새로운 공부를 할 수 있어서 재밌었다!!!
'Develop > Study' 카테고리의 다른 글
UUID (0) | 2025.04.18 |
---|---|
Deserialization Failure due to Date Format (2) | 2025.04.10 |
Spring Framework (0) | 2025.03.14 |
ZeroSSL 인증서 만료 > Let's Encrypt로 재발급 하기 (0) | 2025.02.25 |
Nginx 이용해서 리버스 프록시 설정하기 (2) | 2024.12.27 |