Intersection
Intersection은 Union과 관련은 있는데, 사용방법이 다르다
Intersection은 객체 타입을 하나로 결합하는데 사용된다.
그래서 기존 객체 타입들을 합쳐서 필요한 모든 특성을 갖춘 타입을 하나 얻을 수 있다.
& 로 타입끼리 연산시키면 된다.
예를 들어서 Person & Serializable & Loggable 은 세 타입들을 모두 포함하는 객체 타입이다.
그래서 이 타입의 객체가 세 타입의 모든 특성을 다 갖고 있다는 것을 의미한다.
즉, Person, Serializable, Loggable 세가지 타입의 모든 속성을 가지고 있어야 한다.
예시
interface Admin {
name: string;
privileges: string[];
};
interface Employee {
name: string;
startDate: Date;
};
type ElevatedEmployee = Admin & Employee;
const e1: ElevatedEmployee = {
name:'Max',
privileges: ['create-server'],
startDate: new Date()
};
위 예시처럼, intersection 연산을 통해 두 객체의 속성이 모두 합쳐진 새로운 객체타입을 만들 수 있다.
참고로 interface의 extends 연산으로도 가능하다.
근데 더 간단하게 사용할 수 있는건 intersection 연산이다.
interface ElevatedEmployeeInterface extends Employee, Admin {}
Type Guard
타입 가드란 특정 프로퍼티나 메서드를 사용하기 전에 그것들이 존재하는지 확인하거나
타입을 사용하기 전에 이 타입으로 어떤 작업을 수행할 수 있는지 확인하는 개념이다.
예를 들어 덧셈 함수를 만들때 받은 인자가 숫자인지 문자열인지 확인하여 타입마다 동작을 다르게 하는 것에 타입 가드가 이용된다.
typeof
type Combinable = string | number;
function add(a: Combinable, b: Combinable) {
if(typeof a === "String" || typeof b === "String"){
return a.toString() + b.toString();
}
return a+b;
}
이런 방식으로 typeof 타입 가드를 이용할 수 있다.
유니온 타입은 종종 런타임에서 어떤 타입을 얻어야 할지 정확히 알아야 할 필요가 있어서 타입 가드를 사용해야 할 때가 많다.
이러면, 저 조건문의 상황 외에는 a,b 가 number인 것을 타입스크립트가 알게된다.
유니온 타입이 지닌 장점과 함께 런타임에 코드가 정확히 돌게 해준다.
주의할 점은 typeof null 은 null을 반환하진 않을것이다. (아마 object)
in
typeof 타입가드 말고 in 을 사용하는 방법도 있다.
in 연산자는 객체에 프로퍼티가 있는지 확인해주는 연산자이다.
"property" in someObject
// true || false
그래서 객체간의 유니온 타입으로 얻어진 새로운 타입에 대해 유용하게 사용해볼 수 있다.
프로퍼티가 있는지에 따라 동작을 다르게 할 수 있는 것이다.
type Admin = {
name: string;
privileges: string[];
};
type Employee = {
name: string;
startDate: Date;
};
type UnKnownEmployee = Employee | Admin;
function printInformation(emp : UnKnownEmployee){
console.log("Name " + emp.name);
if( "privileges" in emp ){
console.log("Privileges " + emp.privileges);
}
if( "startDate" in emp ){
console.log("Start Date" + emp.startDate);
}
}
Discriminated Union
union타입에선 타입가드를 사용할 수도 있지만 Discriminated Union을 구축해서 이용할수도 있다.
객체의 경우 유용하게 작용할 수 있다.
예시
interface Brid{
flyingSpeed: number;
}
interface Horse{
runningSpeed: number;
}
type Animal = Brid | Horse;
function moveAnimalWithIn(animal: Animal){
if ('flyingSpeed' in animal){
console.log('Moving with speed: ' + animal.flyingSpeed)
}
if ('runningSpeed' in animal){
console.log('Moving with speed: ' + animal.runningSpeed)
}
}
지금 예시는 동물의 객체마다 속도를 나타내는 프로퍼티의 이름이 다르다.
물론, 키를 speed로 맞춰주는 방법도 있지만 추상화를 한다는 측면에서는 적절하지 못하다고 할 수 있다.
위 방법처럼 in 타입가드를 사용해서 해결할 수 있다
그런데 오타로 인한 문제가 발생할 수 있을 것이다.
그래서 어떤 특성을 지니는지 구체적으로 나타내는 프로퍼티를 지정해주어 Discriminated Union을 구축해볼 수 있다.
nterface DiscriminatedBird{
type: 'bird';
flyingSpeed: number;
}
interface DiscriminatedHorse{
type: 'horse';
runningSpeed: number;
}
type DiscriminatedAnimal = DiscriminatedBird | DiscriminatedHorse;
// 이후 스위치문을 이용해서 아래처럼 할 수 있다.
function moveAnimalWithDiscriminated(animal: DiscriminatedAnimal){
let speed;
switch (animal.type){
case 'bird':
speed = animal.flyingSpeed;
break
case 'horse':
speed = animal.runningSpeed;
break
}
console.log('Moving at speed' + speed);
}
이렇게 유니온을 구성하는 모든 객체에 하나의 공통 속성을 두고 그 속성이 객체를 설명하게 하면 된다
그리고 switch문에서 타입 안정성을 갖추고, 객체에 어떤 속성을 사용할 수 있는지 파악할 수 있다.
Index Properties
인덱스의 타입또한 지정할 수 있다.
객체를 만들 때 포맷을 제한할 수 없는 경우가 있을 수 있다.
어떤 키를 가질지, 몇개의 키를 가질지 사전에 정확하게 지정해줄 수 없을때 인덱스 타입을 조정하면 된다.
interface SomeObject {
[prop: string]: string;
}
이렇게 하나 만들어두면 몇개가 들어오게 될지, 어떤 이름을 가질지는 모르겠지만
문자열로 해석될 수 있는 프로퍼티 키에 문자열 값이 들어올 거라는 것을 알려줄 수 있다.
그래서 아래와 같이 미리 지정하지 않아도 인덱스 타입의 양식에만 맞추면 다 허용해준다
const object1: SomeObject = {
'a' : 'abc',
'b' : 'bcd',
'c' : 'cde',
}
현재 예제에서는 키에 숫자를 넣어도 된다.
숫자는 문자열로 해석될 수 있기 때문이다.
만약 인덱스 타입의 키 타입을 number로 놓게되면 숫자 키만 써야하는 것이다.
reference : 유데미 타입스크립트 강의
'front-end > TypeScript' 카테고리의 다른 글
[TypeScript] AdvancedType - 2 (Type Casting) (0) | 2023.08.08 |
---|---|
[TypeScript] Interface (0) | 2023.08.07 |
[TypeScript] 기본타입 (any, unknown) (0) | 2023.08.06 |
[TypeScript] 기본타입 (함수, 반환, 콜백) (0) | 2023.08.06 |
[TypeScript] 기본타입 (union, literal, typeAlias) (0) | 2023.08.06 |