🎀 Interface의 특별한 기능(e.g extends)이 필요할 때를 빼면
기본적으로 type을 사용하라.
https://www.totaltypescript.com/type-vs-interface-which-should-you-use
Interface는 union 타입, 맵핑된 타입, 조건부 타입을 나타낼 수 없다.
Type은 어떤 타입도 표현 가능.
Interface는 extends 사용 가능, Type은 불가능.
서로를 상속하는 객체를 다룰 때는 Interface 사용 권장.
extends가 & 연산자보다 조금 더 빠르다.
동일 스코프 내에서 동명의 Interface 사용은 선언을 병합시키며
예기치 못한 버그 유발.
Type은 Record<PropertyKey, unknown>라는 implicit index signature를 가진다.
⭐ What is implicit indexing?
: An Implicit index (also known as a null-index) is an index that does not have a name, e.g. a list (a 1-dimensional array). It arises in rare cases in a Definition that contains a subexpression that generates a list of values.
(https://docs.analytica.com/index.php/Implicit_index)
interface Human {
name: string;
age: number;
}
const henry: Human = {
name: '남현욱',
age: 20,
};
//
type Human = {
name: string;
age: number;
};
const henry: Human = {
name: '남현욱',
age: 20,
};
Type Alias 와 Interface 둘 다, Interface에 대한 extends와 Class에 대한 implements 키워드를 사용하여 관계를 정의할 수 있습니다.
(❓❓❓❓❓)
주의점은 객체 타입이나 객체 타입 간 곱 타입(Intersection Type, 교차 타입),
즉 정적으로 모양을 알 수 있는 객체 타입만 동작합니다.
따라서, 합 타입(Union Type, 결합 타입)은 extends와 implements 대신
다른 키워드로 관계를 정의해야 합니다.
| 제목1 | 제목2 |
|---|---|
| 내용1입니다 | 내용2입니다 |
| 내용1 | 내용2 |
어제 더 나은 방법이라고 제시된 코드이긴 한데,
여전히 condition은 두 종류밖에 없다는 전제 하에 동작하고 있어
확장성이 0에 수렴한다.
실제로 향후 프로젝트의 발전 방향을 놓고 볼 때,
배지 추가와 그에 따른 확장성 증대는 필수불가결이라고 생각하므로
더 고민하기로 한다.
const badgesState = useMemo(() => {
return totalBadges.map((badgeGroup) => {
const badge = { ...badgeGroup[1] };
const matchingCondition = badgeConditions.find((cond) => badge.id.includes(cond.idPart));
const isObtained = matchingCondition
? matchingCondition.condition(
matchingCondition.idPart.includes('다이어리수집가') || matchingCondition.idPart.includes('문구점사장님')
? diaryCount
: membershipDays
)
: false;
badge.isObtained = isObtained;
badge.content = isObtained ? badge.content.replace('false', 'true') : badge.content.replace('true', 'false');
return badge;
});
}, [diaryCount, membershipDays]);
Q : 그럼 이 코드에서 condition 타입의 종류가 2개를 초과할 때는 어떻게 해? 마치 타입 종류가 2개만 있는 것처럼 삼항연산자를 사용하고 있잖아. 확장성이 떨어지지 않아?
A : 맞습니다. 이를 해결하기 위해서는 conditionType에 따라 처리할 값을 선택하는 더 유연한 방법이 필요합니다. 예를 들어, switch 문이나 객체 매핑을 사용하여 확장 가능한 구조로 변경할 수 있습니다.
const badgesState = useMemo(() => {
return totalBadges.map((badgeGroup) => {
const badge = { ...badgeGroup[1] };
const matchingCondition = badgeConditions.find((cond) => badge.id.includes(cond.idPart));
let valueToCheck;
switch (matchingCondition?.conditionType) {
case 'diaryCount':
valueToCheck = diaryCount;
break;
case 'membershipDays':
valueToCheck = membershipDays;
break;
// 추가적인 conditionType에 대해 다른 값을 사용할 수 있습니다.
default:
valueToCheck = null; // 만약 conditionType이 정의되지 않았을 경우
}
const isObtained = matchingCondition ? matchingCondition.condition(valueToCheck) : false;
badge.isObtained = isObtained;
badge.content = isObtained ? badge.content.replace('false', 'true') : badge.content.replace('true', 'false');
return badge;
});
}, [diaryCount, membershipDays]);
const valueMap = {
diaryCount: diaryCount,
membershipDays: membershipDays,
// 다른 conditionType에 대한 값을 추가할 수 있습니다.
};
const badgesState = useMemo(() => {
return totalBadges.map((badgeGroup) => {
const badge = { ...badgeGroup[1] };
const matchingCondition = badgeConditions.find((cond) => badge.id.includes(cond.idPart));
const valueToCheck = matchingCondition ? valueMap[matchingCondition.conditionType] : null;
const isObtained = matchingCondition ? matchingCondition.condition(valueToCheck) : false;
badge.isObtained = isObtained;
badge.content = isObtained ? badge.content.replace('false', 'true') : badge.content.replace('true', 'false');
return badge;
});
}, [diaryCount, membershipDays]);
객체를 사용하여 conditionType과 관련된 값을 매핑.
이렇게 하면 새로운 conditionType이 생겨도,
객체에 추가만 하면 되므로 확장성을 개선할 수 있다.