[TypeScript] 타입 별칭, 함수(this, overloading)
타입 별칭 (Alias)
type 키워드를 사용하여 타입에 별도 이름(별명) 을 부여한다.
할당 연산자를 붙여줘야한다.
type TypeA = string
단일 타입에 별칭을 부여하는 것은 크게 유용하지 않다.
type TypeB = string | number | boolean
타입 별칭은 단일 타입보다는 union( | )이나 ampersan0d( &) 기호를 사용하는 intersection 타입에서 별칭을 부여하여 재사용하는데 사용하는게 좋다.
type TypeA = string
type TypeB = string | number | boolean
type User = {
name: string
age: number
isValid: boolean
} | [string, number, boolean]
const userA: User = {
name: 'ohzl',
age: 27,
isValid: true
}
const userB: User = ['msns', 30, false]
function someFunc(param: TypeB) : TypeA {
switch (typeof param){
case 'string':
return param.toUpperCase()
case 'number':
return param.toFixed(2)
default:
return true // error: string 타입을 반환해야한다.
}
}
객체 데이터의 type을 지정할 때 인터페이스 ? 타입 별칭 ? 어떤 것을 사용해야할까
type TypeUser = {
name: string
age: number
isValid: boolean
}
interface InterfaceUser {
name: string
age: number
isValid: boolean
}
const userA: TypeUser = {
name: 'ohzl',
age: 27,
isValid: true
}
const userA: InterfaceUser = {
name: 'ohzl',
age: 27,
isValid: true
}
문법의 차이점은 타입 지정을 할 때는 할당연산자를 사용해야 한다는 것이다.
기능적으로는 큰 차이가 없고 취향에 맞게 사용할 수 있다.
굳이 권장을 하자면 인터페이스 방식을 권장한다.
단지 type 별칭은 객체 데이터의 타입을 만드는 구조라기 보다는 다양한 타입의 별칭을 지정하는 용도라서 사용 범위가 넓은데
인터페이스는 함수나 배열도 지정할 수 있지만 기본적으로는 객체 데이터를 전제하므로 굳이 추천하자면 인터페이스를 추천한다.
그렇다면 인터페이스와 타입별칭의 차이점도 알아보자
1. 확장 가능성
타입 별칭은 새 속성을 추가하기 위해 다시 열 수 없지만, 인터페이스는 항상 확장 가능하다.
interface Animal {
name: string;
}
interface Bear extends Animal {
honey: boolean;
}
const bear = getBear();
bear.name;
bear.honey;
인터페이스는 ‘extends’라는 키워드로 자신에게 주어진 메서드와 변수 정의의 범위 자체를 늘려나간다.
type Animal = {
name: string;
};
type Bear = Animal & {
honey: Boolean;
};
const bear = getBear();
bear.name;
bear.honey;
타입 별칭은 집합 연산의 개념으로 (‘&’, ‘|’) 교집합, 합집합의 개념으로 자신의 범위를 늘려간다.
2. 이름 중복 사용
인터페이스는 이름을 중복으로 선언하면 내용을 합친다 (선언 병합)
타입 별칭은 이름을 중복으로 사용할 수 없다.
3. 사용할 수 있는 타입의 차이
인터페이스는 주로 객체 타입을 정의한다.
타입 별칭은 중복된 타입 코드를 줄이고 주요 데이터 타입 / 인터섹션 타입 / 유니언 타입 등을 정의하는데 사용한다.
type PartialPointX = { x: number };
type PartialPointY = { y: number };
// intersection
type IntersectionPoint = PartialPointX & PartialPointY;
// union
type UnionPoint = PartialPointX | PartialPointY;
// tuple
type Data = [number, string];
함수 - 명시적 this
interface Cat {
name: string
age: number
}
const cat : Cat = {
name: 'ohzl',
age: 27
}
function hello(message: string){
console.log(`Hello ${this.name}, ${message}`)
}
hello.call(cat, 'Your are pretty awesome!')
hello 함수는 일반 함수이므로 this 는 호출 위치에서 정의가 되면서, this는 cat 객체 데이터가 된다.
위의 코드에서 this가 명시되지 않았기 때문에 타입 에러가 발생한다.
interface Cat {
name: string
age: number
}
const cat : Cat = {
name: 'ohzl',
age: 27
}
function hello(this: Cat, message: string){
console.log(`Hello ${this.name}, ${message}`)
}
hello.call(cat, 'Your are pretty awesome!')
// 'Hello ohzl, Your are pretty awesome!'
명시적으로 this의 타입을 지정할 수 있다. ( 매개변수로 취급 X )
함수 - 오버로딩 (Overloading)
예시 1
function add1(a: string, b: string) {
return a + b
}
function add2(a: number, b: number) {
return a + b
}
add1('hello', 'world')
add2(1,2)
add1('hello', 2) // 2 Error
add2('hello', 2) // 'hello' Error
기본적 구조가 같은데 각각의 매개변수가 처리해야 되는 타입이 다른 경우에 함수를 나눠서 사용할 수도 있지만,
함수 오버로딩 방법을 활용하면 함수를 단순하게 관리할 수 있다.
예시 2
function add(a: string, b: string): string // 타입 선언 1
function add(a: number, b: number): number // 타입 선언 2
function add(a: any, b: any) { // 함수 구현
return a + b
}
add('hello', 'world')
add(1,2)
add('hello', 2) // error
add(1, 'world) // error
문자 데이터만 받고 문자만 반환하는 타입, 숫자 데이터만 받고 숫자만 반환하는 타입 두 개가 선언되어 있으며
구현 함수에서 로직을 처리한다.
정리
예시1에서 기본적인 로직과 매개변수의 이름이나 개수도 똑같은 구조의 함수를 타입이 다르다는 이유로 함수 두 개로 나뉘었는데,
함수의 오버로딩을 사용하게 되면 함수를 하나의 이름으로 만들어서 함수가 호출될 때 사용되는 타입만 분기해주면 된다.
⭐
타입선언 1, 타입 선언 2번에 해당하는 각각의 매개변수가 함수 구현과 일치하게 만들어줄 수 있는 방법이다.
함수 구현에 any라는 타입은 실제 타입이라기 보다는 위의 두가지 타입 선언의 내용이 어떤 방식으로든 할당이 될 수 있다라는 의미
참고
https://funes-days.com/dev/difference-of-type-alias-and-interface-in-typescript