![Typescript 변수 타입](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FexDXqp%2FbtsASFNKnlS%2FiD2tYZXFKoiBfRJ2VUOKd0%2Fimg.png)
2023.11.26 - [백엔드/Typescript] - Typescript 컴파일 설정 - tsconfig.json
필요 배경 지식
- 프로그래밍 언어의 기본 데이터 타입
any 타입
any 타입을 사용하는 이유
기본적으로 Javascript가 변수에 어떤 값이든 재할당 가능하다. (기본적으로 any 타입으로 정해져있다고 보면 될듯.)
다만, 그런 단점을 해소하기 위해서 Typescript는 명시적으로 데이터 유형을 설정해서 정적 형 지정 언어로 타입을 지정해 사용하는것이 권장된다.
그러면 Typescript에서 any 타입을 지원하는 이유는 뭘까?
어플 개발시에 어떤 타입을 할당해야할 지 모르는 경우도 있다. 다음과 같은 경우다.
- 외부 라이브러리를 사용하는 경우
- 동적 콘텐츠를 사용하는 경우
//////////////////////////////////////////////////
// 01. 명시적(Explicit) any 타입 지정
//////////////////////////////////////////////////
let explicit_type;
explicit_type = true;
explicit_type = 'OK!';
console.log('explicit_type:', explicit_type);
//////////////////////////////////////////////////
// 02. 암시적(Implicit) any 타입 지정
//////////////////////////////////////////////////
let implicit_type = false;
implicit_type = 'No!';
console.log('implicit_type:', implicit_type);
Tuple 타입
Tuple은 Javascript에서는 지원하지 않는 데이터 타입이라고 한다.
다만, Typescript에서는 배열 타입을 보다 특수한 형태로 사용할 수 있는 tuple 타입을 지원한다. (즉, 배열의 서브 타입이다)
tuple에 명시적으로 지정된 형식에 따라 아이템 순서를 설정해야하고, 추가되는 아이템 또한 tuple에 명시된 타입만 사용가능하다.
let book__name_price:[string, number] = ['카밍 시그널', 13320];
// [오류]
// [ts] '[number, string]' 형식은 '[string, number]' 형식에 할당할 수 없습니다.
// 'number' 형식은 'string' 형식에 할당할 수 없습니다.
// let book__name_price: [string, number]
book__name_price = [13320, '카밍 시그널'];
// [오류]
// [ts] 'false' 형식의 인수는 'string | number' 형식의 매개 변수에 할당될 수 없습니다.
book__name_price.push(false);
tuple 사용시에 타입이 정해져있는 특징 탓에 javascript에서는 지원하지 않는듯.
Tuple 사용 방법 여러 케이스
1. 튜플 요소 사용
아래와 같이 각 요소에 접근해서 해당 타입의 메소드를 사용할 수 있다.
let myTuple: [string, number];
myTuple = ["hello", 10]; // 올바른 할당
console.log(myTuple[0].substring(1)); // "ello"
console.log(myTuple[1].toFixed(2)); // "10.00"
2. 선택적 튜플 요소
"number?" 는 두 번째 요소가 선택적임을 나타낸다고 한다.
즉, 이 요소는 있어도 없어도 된다.
let myOptionalTuple: [string, number?];
myOptionalTuple = ["hello"]; // 유효함
myOptionalTuple = ["hello", 10]; // 유효함
사실 이 기능은 오히려 개발시에 혼란을 줄수도 있을것같다.
차라리 명시적으로 다 존재하는게 좋을것 같기도함.
3. 나머지 요소를 가진 튜플
let myRestTuple: [string, ...number[]];
myRestTuple = ["hello", 10, 20, 30]; // 유효함
"...number[]" 는 두번째 요소부터 끝까지 숫자 배열을 의미한다.
튜플을 사용하면 다양한 타입의 요소를 고정된 길이로 관리 할 수 있고, 함수의 리턴타입으로도 자주 사용된다.
함수 매개변수 타입
tsconfig.json에 noImplicitAny 설정값이 true 인경우, 명시적으로 타입 설정을 하지 않아 다음 코드는 컴파일시 오류가 날 수 있다.
// [오류]
// [ts] 'id' 매개 변수에는 암시적으로 'any' 형식이 포함됩니다.
// (parameter) id: any
// [ts] 'name' 매개 변수에는 암시적으로 'any' 형식이 포함됩니다.
// (parameter) name: any
function setInfo(id, name) {
return { id, name };
}
let product_one = setInfo(120912, '스노우보드');
유니온 타입
id 매개 변수에 설정 가능한 타입 값을 number, string 모두 가능하게 하려면 파이프(|)를 사용하여 설정한다. 이를 유니온(union) 타입이라고 부른다.
C 이외에 유니온 타입을 오랜만에 봐서 신기하기도하다 ㅎㅎ
string이나 int가 같이 쓰여지는 경우가 있어서 쓸만한것 같기도하다.
function setInfo(id:number|string, name:string){
return { id, name };
}
함수 리턴 타입
void 는 결과 값을 반환하지 않는 함수에 설정한다.
반변 결과값을 반환하면 명시적으로 반환 타입을 지정할 수 있다.
// 리턴 값 타입이 명시적으로 설정되지 않는 함수
function assignClass(name:string): void {
document.documentElement.classList.add(name);
}
// 리턴 값 타입이 숫자인 함수
function factorial(n:number): number {
if (n < 0) { return 0; }
if (n === 1) { return 1; }
return n * factorial(n-1);
}
// 리턴 값 타입이 문자인 경우
function repeat(text:string, count:number=1): string {
let result:string = '';
while(count--) { result += text; }
return result;
}
함수 식
명시적으로 함수에 설정 가능한 타입을 정의하고자 한다면 다음과 같이 작성 가능하다고 한다.
// 변수에 함수 매개변수, 리턴 타입에 대한 명시적 설정
let assignClass: (n:string) => void;
// 변수에 함수 값 할당
assignClass = function(name) {
document.documentElement.classList.add(name);
};
함수 값 할당 구문을 별도로 나누지 않고 한번에 정의할 수 도 있다.
let factorial:(n:number)=>number = function (n) {
if (n < 0) { return 0; }
if (n === 1) { return 1; }
return n * factorial(n-1);
};
개인적으로 Typescript 사용시에 GPT나 Copilot은 이 부분을 자주 생성해줬었는데 정확한 문법을 몰라서 헷갈렸었다.
같은 코드를 아래와 같이 생성해줬었다.
let factorial:(n:number)=>number = n => {
if (n < 0) { return 0; }
if (n === 1) { return 1; }
return n * factorial(n-1);
};
혹은 이런식으로 한줄로도 작성해줬다.
let factorial:(n:number)=>number = n => n < 0 ? 0 : n === 1 ? 1 : n * factorial(n-1);
Object 타입
Typescript에서는 변수에 초기 설정된 값을 암시적으로 할당 가능한 데이터 타입으로 설정한다고 한다.
let Dom = {
version: '0.0.1',
el(){},
css(){}
};
// [오류]
// [ts]
// '{ append(): void; }' 형식은 '{ version: string; el(): void; css(): void; }' 형식에 할당할 수 없습니다.
// 객체 리터럴은 알려진 속성만 지정할 수 있으며 '{ version: string; el(): void; css(): void; }' 형식에 'append'이(가) 없습니다.
// (method) append(): void
Dom = {
append(){}
};
그래서 객체의 각 속성별 타입을 명시적으로 아래와 같이 작성할 수도 있다.
let Dom = {
version: '0.0.1',
el(){},
css(){}
};
// [오류]
// [ts]
// '{ append(): void; }' 형식은 '{ version: string; el(): void; css(): void; }' 형식에 할당할 수 없습니다.
// 객체 리터럴은 알려진 속성만 지정할 수 있으며 '{ version: string; el(): void; css(): void; }' 형식에 'append'이(가) 없습니다.
// (method) append(): void
Dom = {
append(){}
};
null / undefined 타입
Javascript에서 null, undefined는 데이터 타입 이자 하나의 값이다.
Typescript에서도 하나의 타입으로 처리되고 다음과 같이 사용할 수 있다.
let nullable:null = null;
let undefinedable:undefined = undefined;
null로 명시적 타입이 설정된 변수에 null이 아닌 값이 할당되면 오류를 출력한다.
// [오류]
// [ts] 'undefined' 형식은 'null' 형식에 할당할 수 없습니다.
// let nullable: null
nullable = undefined;
이런 엄격한 오류 출력의 이유는 tsconfig.json에 정의 되어 있기 때문이다.
다음과 같은 설정으로 정의가 가능하다.
"strictNullChecks": true, /* 엄격한 null 검사 사용 */
이를 설정하면 모든 데이터 타입은 null, undefined를 할당 받을 수 없다.
따라서 이를 해결하려면 any 혹은 union 타입으로 사용해야한다.
하지만 any를 사용하면 특정 타입으로 설정하는게 아니므로 유니온 타입을 사용하는것이 더 적절하다.
// let assign_name:any = null;
let assign_name:string|null = null;
if (!assign_name) {
assign_name = '미네랄';
}
never 타입
never는 일반적으로 함수의 리턴타입으로 사용된다.
함수의 리턴타입으로 never가 사용될 경우, 항상 오류를 출력하거나 리턴값을 절대로 내보내지 않음을 의미한다.
무한루프에 빠지는것과 같다고 한다.
// 항상 오류 발생
function invalid(message:string): never {
throw new Error(message);
}
// never 타입을 결과 추론(Inferred)
function fail() {
return invalid('실패');
}
// 무한 루프
function infiniteAnimate(): never {
while ( true ) { infiniteAnimate(); }
}
사용자 정의 타입
다른 언어의 struct나 클래스 같이 사용자가 직접 정의한 타입도 생성할 수 있다고 한다.
위의 모든 타입들을 응용해서 만들면 될것같다.
예시는 아래와 같다.
// 사용자 정의 타입 operation 정의
// 타입 별칭(Type Alias)
type operation = {
data: number[],
output:(num:number)=>number[]
};
// 사용자 정의 타입 operation 적용 예시
let sum:operation = {
data: [10, 30, 60],
output(num){
return this.data.map(n=>n+num);
}
};
let multiply:operation = {
data: [110, 230, 870, 231],
output(num){
return this.data.map(n=>n*num);
}
};
타입 어설션 (Assertion)
타입 어설션은 컴파일러에게 "이 타입이 특정 타입이여야 한다" 고 하는것과 같다.
컴파일 과정에서만 사용된다고 한다.
사용방법
앵글 브라켓 <>
let assertion:any = "타입 어설션은 '타입을 단언'합니다.";
// 방법 1: assertion 변수의 타입을 string으로 단언 처리
let assertion_count:number = (<string>assertion).length;
as 문법 사용
let assertion:any = "타입 어설션은 '타입을 단언'합니다.";
// 방법 2: assertion 변수의 타입을 string으로 단언 처리
let assertion_count:number = (assertion as string).length;
결론
- Typescript에 정의된 다양한 타입에 대해서 알아보았다.
- 이를 잘 숙지하고 다음 코드 작성에 반영해보도록 하자! ㅎㅎ
Reference
타입 - TypeScript Guidebook
"도로 차선" 예시를 들어봅시다. 각 차로에 제한을 두지 않고 자유롭게 차로를 이용할 수 있다면 편할 겁니다. 하지만 자유로운 만큼 사고가 발생할 확률 또한 커집니다. 하지만 각 차로에 접근
yamoo9.gitbook.io
'백엔드 > NodeJS | Typescript' 카테고리의 다른 글
Typescript 프로젝트의 naming convention (0) | 2023.12.07 |
---|---|
Typescript 이해하기 - Async/Await 이해하기 (0) | 2023.11.28 |
Typescript 이해하기 - 제너레이터 이해하기 (0) | 2023.11.28 |
Typescript 이해하기 - Promise 이해하기 (0) | 2023.11.27 |
Typescript 컴파일 설정 - tsconfig.json (0) | 2023.11.26 |
개발 및 IT 관련 포스팅을 작성 하는 블로그입니다.
IT 기술 및 개인 개발에 대한 내용을 작성하는 블로그입니다. 많은 분들과 소통하며 의견을 나누고 싶습니다.