// UnionfunctionprintId(id:number|string){console.log(id.toUpperCase());// if (typeof id === "string") {// // In this branch, id is of type 'string'// console.log(id.toUpperCase());// } else {// // Here, id is of type 'number'// console.log(id);// }}
TypeScript
복사
◦
id라는 변수는 number 또는(or ⇒ |) string 타입을 가질 수 있음을 명시
◦
해당 함수에 전달되는 파라미터 id는 숫자나 문자열 타입 일 수 있다는 의미
◦
→ 하지만 함수 실행부에서 각 타입일 때에 대한 후속 처리도 필요하다는 의미
▪
각 타입일 경우에 대해서 실행부를 좁히는 것을 Narrowing 이라 하며 주석 부분과 같이 상황별 대처를 조건문으로 처리해주는 등이 필요
•
하지만, 이런 기능이 있더라도 이런 코드가 좋은 코드인지 생각해볼 필요가 있음
◦
함수(메서드)는 역할에 맞는 한가지의 일만 하도록 구성해야 한다. by CleanCode
▪
모듈은 복잡도, 결합도를 낮춰야 하며, 응집도를 높여야 한다.
▪
→ 재사용성을 증가 시키며 이는 곧 유지보수성을 증가 시킨다.
◦
실행부에서 분기하는 것 보다, 거의 동일한 코드가 중복되더라도 정확한 메서드를 분리하는 것이 옳은 판단 일 수 있다.
하지만 타입은 기본형 타입만 있지 않다. 객체도 타입이 될 수 있고 따라서 수없이 많은 함수를 생성해야 하게 될 것이다.
•
이런 비효율적인 상황을 대처하기 위한 것이 Generics이다.
◦
< > 안에 작성된 키워드가 해당 함수에 동일한 표현들을 동적으로 통일시킨다는 것을 나타냄
◦
통일 될 최초 타입은 키워드가 작성된 Parameter(매개변수)의 타입이 기준이 되며 해당 블록의 키워드가 포함 된 타입들은 모두 이를 따르게 됨
// Use Genericsfunctionidentity<Type>(arg: Type): Type {return arg;}
TypeScript
복사
◦
Type이란 키워드 대신 T라는 키워드로 대체하여 사용하는 경우가 많음
// Use Genericsfunctionidentity<T>(arg:T):T{return arg;}
TypeScript
복사
◦
참고 : 여기 표현된 Type 또는 T(or U or V …) 는 실제 있는 자료형(타입) 이 아니다. 자유롭게 지정 할 수 있어 타입 별칭(Type Alias)과 혼동 될 수 있지만 다른 기능
▪
관례적으로 T를, 매개 변수가 2개 이상을 제너릭으로 표현해야 하는 경우엔 이후로는 U, V, W 등을 자주 사용한다.
functionidentity<T,U>(arg1:T, arg2:U):[T,U]{return[arg1, arg2];}const result =identity(20,"Hello");// result는 [number, string] 타입
TypeScript
복사
◦
정확히 구분 되는지 테스트
functionisNumber(value:any){returntypeof value ==='number'&&!isNaN(value);}functionisString(value:any){returntypeof value ==='string';}// isArray는 Array의 내장 함수 사용// 간단 테스트// givenconst testValue1:number=20;const testValue2:string="Hi";const testValue3:number[]=[1,20];// when 1const numberIdentity =identity(testValue1);// number 타입// then 1console.log(`Input type is : ${typeof testValue1}`);console.log(`Output type is : ${typeof numberIdentity}`);console.log(`Is number: ${isNumber(numberIdentity)}`);// true// when 2const stringIdentity =identity(testValue2);// string 타입// then 2console.log(`Input type is : ${typeof testValue2}`);console.log(`Output type is : ${typeof stringIdentity}`);console.log(`Is string: ${isString(stringIdentity)}`);// true// when 3const arrayIdentity =identity(testValue3);// number[] 타입// then 3console.log(`Input type is : ${typeof testValue3}`);console.log(`Output type is : ${typeof arrayIdentity}`);console.log(`Is array: ${Array.isArray(arrayIdentity)}`)// true
TypeScript
복사
◦
Generics를 사용한 identity() 함수가 예상대로 작동하는지 확인해보자.
▪
테스트코드 작성의 Given-When-Then 패턴
▪
준비-실행-검증의 단계로 테스트의 흐름이 명확하고, 각 단계에서 어떤 작업이 이루어지는지 쉽게 이해하기 위한 표현 기법
•
Given: 테스트에 필요한 초기 데이터를 설정
•
When: 테스트를 실행하는 부분으로, identity 함수를 호출
•
Then: 각 입력값에 대한 결과를 검증하고 출력
•
제너릭을 실제로 구현하고, 사용하기 어려울 수도 있지만, 알고 있어야 하는 이유
◦
Array와 같은 내장 라이브러리를 살펴보자.
◦
우리가 사용하는 많은 함수, 메서드, 라이브러리 등은 이처럼 구현되어 있기 때문에 이는 다양한 데이터 타입을 쉽게 사용 할 수 있도록 구현되어 있다.
◦
필요에 따른 튜닝, 검토 등을 위해 내부 구조를 살펴보게 될 때 이해 할 수 있어야 한다.