Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- ios
- react-native
- react-native-permissions
- Swift
- react native
- React-Native업데이트
- debounce
- react animation
- Hash-table
- named type
- rn
- RN새로운아키텍쳐
- private-access-to-photos
- 비동기
- react
- async
- promise.all
- react-native-image-picker
- RN아키텍쳐
- javascript
- motion.div
- axios
- await
- CS
- no-permission-handler-detected
- Throttle
- Promise
- animation
- hydration mismatch
- RN업데이트
Archives
- Today
- Total
하루살이 개발일지
[TypeScript] type과 interface의 차이점 본문
Type Aliases 에 대하여
TypeScript에서의 기본 type
- 타입스크립트에 존재하는 기본 타입
String
Boolean
Number
Array
Tuple
Enum
Advanced types
타입 별칭(Type Aliases)
- 특정 타입이나 인터페이스를 참조할 수 있는 타입 변수
- type 키워드를 붙여 만듦
- 새로운 타입 값을 생성하는 것이 아닌 정의한 타입에 대해 나중에 쉽게 참고할 수 있게 ‘이름’을 부여한 것과 같음
type MyNumber = number;
type User = {
id: number;
name: string;
email: string;
}
Type Aliases의 특징
type ErrorCode = string | number;
type Answer = string | number;
- union ( | ) 을 사용해 두 개 이상의 원시 타입을 결합할 수 있음
- interface 에는 이 기능이 없음
- 현재 ErrorCode와 Answer은 같은 union type ( string | number ) 이지만, 이렇게 구분지음으로써 다른 의도로 사용될 것을 암시 ⇒ 코드 가독성이 높아짐
Interfaces에 대하여
객체의 타입을 정의하는 interface
interface Client {
name: string;
age: number;
}
//interface를 바탕으로 객체 생성
let user: Client = {
name: "John Doe",
age: 30
};
- interface는 객체가 어떤 프로퍼티를 가지고, 각 프로퍼티의 타입은 무엇인지 명시함
type Client = {
name: string;
address: string;
};
- 이는 type 을 사용해서도 구현할 수 있음
type과 interface의 차이점
type을 쓰는 게 더 좋은 경우
1. 원시형 타입 (primitive types)
- 원시형 타입 : number, string, boolean, null, undefined 타입
type Address = string;
type NullOrUndefined = null | undefined;
- type alias를 이용하면 원시형 타입, union 타입을 쉽게 정의할 수 있음
type WindowStates = "open" | "closed" | "minimized"; // 가능
interface WindowStates = "open" | "closed" | "minimized"; // 에러
- interface에서는 이것이 불가능
- interface는 객체 유형만 사용 가능하기 때문
2. Union types
- Union types : TypeScript에서 특정 변수가 여러 타입 중 하나를 가질 수 있는 것을 표현하는 방법
- | 문자를 사용해 만듦
type Transport = 'Bus' | 'Car' | 'Bike' | 'Walk';
- Transport 타입의 면수가 'Bus', 'Car', 'Bike', 'Walk' 중 하나만 가질 수 있음을 의미
interface CarBattery {
power: number;
}
interface Engine {
type: string;
}
type HybridCar = Engine | CarBattery;
- 인터페이스를 사용해 Union type을 직접 만드는 것은 불가능
- 하지만, 두 개 이상의 인터페이스를 결합해 새로운 유니온 타입을 생성하는 것은 가능
- CarBattery 인터페이스와 Engine 인터페이스를 결합해 HybridCar 유니온 타입을 만들 수 있음
- HybridCar 유니온 타입의 변수
- Engine 인터페이스 또는 CarBattery 인터페이스 형태를 가질 수 있음
- 즉, 하이브리드 자동차가 엔진 또는 배터리로 작동할 수 있다는 의미와 동일
3. Function types
- 타입스크립트에서 함수 타입을 정의하려면 매개변수와 반환 타입을 지정해야 함
type AddFn = (num1: number, num2:number) => number;
interface IAdd {
(num1: number, num2:number): number;
}
- type과 interface는 모두 함수 타입을 정의할 수 있음
- 인터페이스는 : 를 사용하고, type은 ⇒ 를 사용함
- type이 더 짧고 가독성이 좋아 type이 선호됨 (무조건적은 아님!)
- type을 쓰는 또 다른 이유
- 함수가 복잡해지면 → 조건부 타입(conditional types), 매핑된 타입(mapped types) 등 고급 타입 기능을 활용할 수 있어서
type Car = 'ICE' | 'EV';
type ChargeEV = (kws: number)=> void;
type FillPetrol = (type: string, liters: number) => void;
type RefillHandler<A extends Car> = A extends 'ICE' ? FillPetrol : A extends 'EV' ? ChargeEV : never;
const chargeTesla: RefillHandler<'EV'> = (power) => {
// Implementation for charging electric cars (EV)
};
const refillToyota: RefillHandler<'ICE'> = (fuelType, amount) => {
// Implementation for refilling internal combustion engine cars (ICE)
};
- union type인 Car / 함수 타입 ChargeEV & FillPetrol
- Car는 ICE, EV 값 중 하나를 가질 수 있는 union type
- ICE는 내연 기관 차, EV는 전기차를 의미
- ChargeEV 타입 ⇒ kws(전기량) 을 매개변수로 받아 아무것도 반환하지 않는 함수 (void)
- FillPetrol 타입 ⇒ type(연료 종류), liters(리터 수) 매개변수, void
- Car는 ICE, EV 값 중 하나를 가질 수 있는 union type
- 조건부 타입 RefillHandler
- A extends Car : Car 타입을 확장하는 제네릭 타입 A를 매개변수로 받음
- A가 ICE일 경우 FillPetrol 타입의 함수를 반환
- A가 EV일 경우 ChargeEV 타입의 함수를 반환
- A가 ICE, EV가 모두 아닌 경우는 없으므로 never (컴파일 타임에서 안정성 보장 위함)
- A extends Car : Car 타입을 확장하는 제네릭 타입 A를 매개변수로 받음
- RefillHandler 타입에 ICE나 EV를 제네릭을 제공하면 해당 함수 타입이 결정됨
- chargeTesla와 refillToyota에 각각 EV, ICE를 제네릭으로 제공하면 RefillHandler 타입은 각각 ChargeEV 타입과 FillPetrol 타입의 함수를 반환하게 됨
- 즉, chargeTesla 함수는 kws(전기량)을 매개변수로 받는 ChargeEV 타입의 함수가 되고, refillToyota 함수는 type, liters를 매개변수로 받는 FillPetrol 타입의 함수가 됨
- 즉, 조건부 타입과 union type을 활용하면 서로 다른 시그니처를 가진 함수를 처리할 수 있음
interface를 쓰는 게 더 좋은 경우
Declaration merging
- Declaration merging : TypeScript에서 인터페이스가 갖는 특징
- 동일한 인터페이스를 여러 번 정의할 수 있음
- TS 컴파일러가 이러한 정의들을 자동으로 하나의 인터페이스 정의로 merge
interface Client {
name: string;
}
interface Client {
age: number;
}
const harry: Client = {
name: 'Harry',
age: 41
}
- 두 번 선언된 Client
- TS 컴파일러에 의해 하나로 merge됨
- 그 결과 Client 인터페이스를 사용할 때 두 개의 프로퍼티가 있게 됨
- 반면, type aliases는 같은 방식으로 merge될 수 없음
- 위와 같이 Client type을 한 번 이상 정의하면, 에러가 발생
declaration merging의 일반적인 사례
- 서트파티 라이브러리의 타입 정의를 확장할 때
ex) 서드파티 라이브러리 사용중이고, 해당 라이브러리 특정 타입에 프로퍼티를 추가하려고 할 때
// node_modules/library/index.d.ts 에서 가져온 타입
interface ThirdPartyType {
prop1: string;
}
// 우리의 프로젝트 파일 내에서 이 타입을 확장
interface ThirdPartyType {
newProp: number;
}
// 이제 ThirdPartyType은 우리가 추가한 프로퍼티도 포함하게 됨
const item: ThirdPartyType = {
prop1: "Hello",
newProp: 42
};
- ThirdPartyType 를 declaration merging 함으로써 ThirdPartyType 인터페이스에 newProp이라는 새로운 프로퍼티를 추가
- 이렇게 하면, 해당 타입을 사용하는 모든 곳에서 새로운 프로퍼티를 사용할 수 있음
- 이는 서드파티 라이브러리 타입에 커스텀 프로퍼티 추가하거나, 라이브러리가 업데이트되어 새로운 프로퍼티가 추가되었지만 타입 정의가 아직 업데이트되지 않은 경우 유용
- 하지만 이는 기존 타입 정의를 변경하는 것이므로 타입 안정성 문제에 주의해야 함
Reference :
https://blog.logrocket.com/types-vs-interfaces-typescript/
https://joshua1988.github.io/ts/guide/type-alias.html#type-vs-interface
'웹개발 > TypeScript' 카테고리의 다른 글
[TypeScript] 제네릭(Generics)에 대하여 (3) | 2023.06.29 |
---|---|
TypeScript로 Create React App (CRA) 프로젝트를 생성 (0) | 2023.06.23 |