일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 테스트 코드
- 개발 공부
- GPU
- React Query
- javascript
- 항해 플러스 프론트엔드
- 항해99
- 알고리즘
- 항해
- FE
- 회고
- 분기 회고
- frontend
- rust
- 성장일지
- 백준
- React
- wil
- naver
- 리뷰
- 항해플러스
- 프론트엔드
- 개발자
- 성능최적화
- 보안
- 항해 플러스
- 개발공부
- 자바스크립트
- webGPU
- typescript
- Today
- Total
느릿늘있
[TypeScript] 오버로딩(Overloading) 본문
타입스크립트를 공부하면서 오버로딩이 조금 특이하게 동작하는 부분이 있는 것 같아서 정리 겸 공유를 위해 기록을 남겨본다. 우선, 자바스크립트는 함수의 매개변수와 리턴타입에 관대하기 때문에 오버로딩이 필요가 없다.
function a (arg) { return arg }
// 에러가 발생하지 않는다.
a(true, 1) // true
a("12", 123, true) // "12"
a() // undefined
타입스크립트에서 타입을 설정하지 않으면 자바스크립트와 동일하게 동작할까?
function a (arg){
console.log(arg)
console.log(typeof(arg))
}
// 매개변수 갯수에 대해 엄격하게 체크한다.
a(1, '2') // error : Expected 1 arg, but got 2
a() // error : Expected 1 arg, but got 0
// arg는 default로 any가 설정되며 타입 추론이 동작한다.
a(1) // 1 number
a('2') // 2 string
이처럼 자바스크립트와는 다르게 타입스크립트는 함수의 매개변수에 대해 타입과 갯수를 체크하는 것으로 보인다. 따라서 다형성을 제공하기 위한 오버로딩 기능을 제공할 것으로 예측할 수 있다. 실제로 타입스크립트에서 함수의 오버로딩 기능을 제공하는 방식은 아래와 같다.
// 1. 매개변수 개수에 대한 오버로딩
function a (arg): void
function a (arg, arg2): void
// optional property 활용
function a (arg, arg2?){
console.log(arg)
console.log(typeof(arg))
console.log(arg2)
console.log(typeof(arg2))
}
a(1) // 1 number undefined undefined
a(1, '2') // 1 number 2 string
a() // error : Expected 1-2 arguments, but got 0.
a(1,2,3) // error : Expected 1-2 arguments, but got 3.
// 2. 매개변수 타입에 대한 오버로딩
function a (arg:string): void
function a (arg:number): void
function a (arg: any){
console.log(arg)
console.log(typeof(arg))
}
a(1) // 1 number
a('2') // 2 string
a(true)
// error : Argument of type 'boolean' is not assignable to parameter of type 'string'.
// error : Argument of type 'boolean' is not assignable to parameter of type 'number'.
두 가지를 혼합해서 개수와 타입에 대해 동시에 오버로딩하도록 할 수도 있다. 그런데 타입스크립트를 조금 써 본 사람들은 뭔가 이상하다고 느낄 것이다. 사실 optional property는 저렇게 굳이 선언부와 구현부를 나누지 않아도 잘 동작한다. 타입에 대한 오버로딩도 저렇게 any를 쓰는 것보다 차라리 선언부 없이 유니온 타입으로 사용하는 것이 더 좋아 보인다. (무분별한 any 타입 사용 지양)
function a (arg: string | number){
console.log(arg)
console.log(typeof(arg))
}
마지막 세번째로 오버로딩은 반환값이 여러 타입일 때는 필요해 보인다. 이펙티브 타입스크립트(댄 밴더캄 저)를 보면 " 사용할 때는 너그럽게 생성할 때는 엄격하게 "라는 타입스크립트 사용 원칙을 제안한다. 쉽게 말해서 함수의 매개변수는 너그럽게 받더라도 반환값은 엄격하게 제한해야 한다는 의미이다. 그러나 실제 개발 시 어쩔 수 없이 하나의 함수가 여러 타입의 값을 반환해야 하는 경우가 있다. 이 때, 오버로딩을 활용하여 특정 상황에서 특정한 값만 반환하도록 엄격하게 제한할 수 있다.
// user의 정보(info)객체 혹은 객체 리스트를 받아서 User 객체 혹은 User 객체의 배열을 반환하는 함수 makeUsers가 있다.
// 단일 객체를 받았을 때는 단일 객체를 반환하고 배열로 받았을 때는 배열로 반환하고 싶다.
interface Info {}
interface User {}
declare function setUser(info: Info): User
function makeUsers(info: any): any {
if (Array.isArray(info)) {
const userList = info.map((data: Info) => setUser(data))
return userList
} else {
const user = setUser(info)
return user
}
}
let info: Info = {}
let infoList: Info[] = [{}, {}]
// 단일객체를 매개변수로 넣든 객체 배열을 넣든 동일한 유니온 타입 반환값을 보여준다.
const a = makeUsers(info) // User | User[]
const b = makeUsers(infoList) // User | User[]
// 오버로딩을 활용하여 정확한 설계 내용을 보여줄 수 있다.
interface Info {}
interface User {}
declare function setUser(info: Info): User
// 아래 오버로딩 함수의 순서를 바꾸면 제대로 동작하지 않는데
// 범위가 큰 함수가 먼저 선언되어야 하는 것 같다.(정확하지 않음)
function makeUsers(info: Info[]): User[]
function makeUsers(info: Info): User
function makeUsers(info: any): any {
if (Array.isArray(info)) {
const userList = info.map((data: Info) => setUser(data))
return userList
} else {
const user = setUser(info)
return user
}
}
let info: Info = {};
let infoList: Info[] = [{}, {}];
// 단일 객체를 넣는 경우와 리스트 객체를 넣는 경우 추론되는 반환값이 다르다.
const a = makeUsers(info) // User
const b = makeUsers(infoList) // User[]
단순한 예제들로 타입스크립트의 오버로딩 기능을 살펴 보았다. 실제 개발 환경에서는 훨씬 더 복잡한 상황들이 많이 펼쳐지겠지만 위 내용들이 적절한 트레이드 오프를 선택하고 판단하는 데 도움이 됐기를 바란다.
'개발공부' 카테고리의 다른 글
[WebGPU]에 대해서 Araboza...(4) (0) | 2023.07.30 |
---|---|
[보안] 서드파티 API 보안 강화를 위한 5가지 (0) | 2023.07.27 |
[SW개념] 일급 시민 (0) | 2023.07.09 |
[WebGPU]에 대해서 Araboza...(3) (0) | 2023.07.04 |
[GIT] commit message prefix (0) | 2023.06.28 |