사용하려는 인터페이스에 대해 일일히 if문으로 타입을 좁히기 힘들다면 implements키워드를 통해 클래스로 인터페이스를 구현하고 형식이 아닌 값이 된 타입을 통해 반복문으로 타입추론을 할 수 있다.
클래스가 인터페이스를 구현하기 위해서는 타겟 인터페이스에 선언된 프로퍼티와 메서드를 반드시 포함해야 한다.
1.기존의 인터페이스
export interface ProvincialEnrollSaveRequestDto {
/**
* 만 3세 인원 수 - 세부타입: 유치원
* @format int32
*/
age3?: number;
/**
* 만 4세 인원 수 - 세부타입: 유치원
* @format int32
*/
age4?: number;
/**
* 만 5세 인원 수 - 세부타입: 유치원
* @format int32
*/
age5?: number;
/**
* 노인 인원 수 - 세부타입: 노인
* @format int32
*/
elderly?: number;
/**
* 교육 시작 희망 일자
* @format date
* @example yyyy-MM-dd
*/
expectedToStartDtime?: string;
/**
* 1학년 인원 수 - 세부타입: 초등학교, 중학교, 고등학교
* @format int32
*/
grade1?: number;
/**
* 2학년 인원 수 - 세부타입: 초등학교, 중학교, 고등학교
* @format int32
*/
grade2?: number;
/**
* 3학년 인원 수 - 세부타입: 초등학교, 중학교, 고등학교
* @format int32
*/
grade3?: number;
/**
* 4학년 인원 수 - 세부타입: 초등학교, 중학교, 고등학교
* @format int32
*/
grade4?: number;
/**
* 5학년 인원 수 - 세부타입: 초등학교, 중학교, 고등학교
* @format int32
*/
grade5?: number;
/**
* 6학년 인원 수 - 세부타입: 초등학교, 중학교, 고등학교
* @format int32
*/
grade6?: number;
/** 소속 */
organization?: string;
/**
* 자가 운전자 인원 수 - 세부타입: 자가운전자
* @format int32
*/
selfDriver?: number;
}
export class PrincialEnrollResponse implements ProvincialEnrollSaveRequestDto {
age3: number;
age4: number;
age5: number;
elderly: number;
expectedToStartDtime: string;
expiredDtime: string;
grade1: number;
grade2: number;
grade3: number;
grade4: number;
grade5: number;
grade6: number;
modifiedDtime: string;
organization: string;
selfDriver: number;
seq: number;
status: number;
userInfo: string;
userSeq: number;
constructor( ) {
this.age3 = 0;
this.age4 = 0;
this.age5 = 0;
this.elderly = 0;
this.expectedToStartDtime = "";
this.expiredDtime = "";
this.grade1 = 0;
this.grade2 = 0;
this.grade3 = 0;
this.grade4 = 0;
this.grade5 = 0;
this.grade6 = 0;
this.modifiedDtime = "";
this.organization = "";
this.selfDriver = 0;
this.seq = 0;
this.status = 0;
this.userInfo = '';
this.userSeq = 0;
}
}
// 내가 클래스 또는 객체를 알고 있을 때 사용.
export const isAllowedType = (type: string): type is keyof PrincialEnrollResponse => Object.keys(new PrincialEnrollResponse()).includes(type);
// 내가 클래스 또는 객체를 모를 때 사용. 키만 사용할 것이기에 값은 any
export const isAllowedType2 = (obj: Record<string, any>, type: string): type is keyof typeof obj => Object.keys(obj).includes(type);
const handleEduPersonCount = ( e: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
const {name, value} = e.target;
// name이 ProvinceEnrollResponse에 포함되어 있지 않다면 return
const isAllowed = isAllowedType(name);
if(!isAllowed) return;
if (value.length > 6) return;
if (value === '') return setValue(name, +value)
if (value.length === 0 || value === '0') return setValue(name, +value);
if (isNaN(+value)) return;
setValue(name, Number(value.replace(/[^0-9]/g, '')));
};
<TextField
onChange={handleEduPersonCount}
name={ap}
value={isAllowedType(ap) ? watch(ap) : 0}
sx={{
marginLeft: '-10px',
mr: '10px',
fontWeight: 'bold',
mb: '4px',
}}
/>
isAllowedType을 사용하지 않는다면?
e.target.name은 string이기에 PrincialEnrollResponse보다 넓은 타입이다. 그러므로 타입을 좁혀주지 않는다면
string은 "" | "" | "" ... 에 포함될수 없으므로 ...ts(2345)에러가 발생한다.
좋은 글 감사합니다.