본문 바로가기
카테고리 없음

TypeScript - 타입스크립트 원시타입 & 유니언타입 정리

by Hynn1429 2023. 4. 23.
반응형

안녕하세요.

Hynn 입니다.

 

이번 포스팅에서는 연속적으로, 원시타입부터, TypeScript 에서 사용할 수 있는 타입의 종류, 작성방법에 대해서 작성해보도록 하겠습니다.

JavaScript 에서는 변수에 담기는 컨텐츠들이 각자 고유의 타입을 가지고 있습니다.

기존에서 JavaScript 의 타입은, 사용자가 추측하여 작성하거나, 어떤 타입이 되었든, 형변환을 통해 사용하는 형태로 사용했다면, TypeScript 에서는 코드 작성자가 타입을 명시해야 하며, 이를 준수하지 않을 경우, 오류가 반환되는 형태로 작성이 필요합니다.

 

시작해보겠습니다.

 

==============

1. 타입에 대해 알아보기

2. 원시타입 & 

3. 유니언타입

4. 타입 작성방법

==============

 

1. 타입에 대해 알아보기

 

JavaScript 에서는 Type 을 확인할 수 있는 아주 간단한 방법이 있습니다. 바로 "Typeof" method 를 사용하여 변수나 값이 어떤 타입을 가지고 있는지를 알 수 있습니다.

예시를 통해 확인하려면 아래와 같이 작성해볼 수 있습니다.

 

const test = () => {
  console.log("test");
};

const test2 = 10n;

console.log(typeof test);
console.log(typeof test2);

기존의 JavaScript 는 Runtime, 즉 코드를 "실행" 해야 결과를 알 수 있고, 오류가 발생하더라도, 실행한 직후에 오류가 발생됩니다.

하지만 TypeScript 는 이름 그대로, 코드를 작성하는 단계부터 Type 을 명시할 수 있고, 명시한 Type 과 일치하지 않으면, 불일치로 인한 오류가 코드 작성단계부터 발생하게 됩니다.

 

또한 이 타입을 사용하면, 코드의 작성 효율을 올릴 수 있습니다.

먼저 이를 이용해 간단한 예시를 살펴보면 아래와 같습니다.

 

각각 JavaScript 와 TypeScript 에서 변수에 Number 라는 타입을 담고, " . " 을 사용하면 나타나는 method 입니다.

이는 매우 단순한 원시타입이기때문에, IDE(Visual Studio Code) 에서 "타입 추론" 을 해서, 두 가지가 큰 차이가 없게 나타나지만, 추론이 되지 않는 단계에서는 매우 유의미한 차이가 있습니다.

 

바로, 내가 지정한 타입에서 어떠한 Method 를 사용할 수 있는지를 간결하고, 확실하게 알 수 있습니다.

즉, TypeScript 에서 작성한 코드에서는, 작성단계에서부터, 명시된 타입에 따른 사용가능한 메서드가 나열되고, 이 메서드를 사용해 오류가 발생한 것이라면, "타입"이 올바르지 않게 반환되었거나, 변수/메서드의 값이 작성자가 명시한 타입이 아니라는 의미로 전달이 되기도 합니다.

 

따라서, TypeScript 에서 타입은 기초적으로 숙지해야 할 매우 중요한 요소라고 할 수 있습니다.

이 타입은, 원시타입을 비롯해서, 여러가지 타입이 있습니다.

이번 포스팅에서는 가장 기본적으로 사용되는 원시타입을 알아보고, 타입별로 어떠한 의미인지를 알아보도록 하겠습니다.

 

2. 원시타입

 

원시타입은, JavaScript 에서 말하는 원시타입과 거의 동일합니다.

이 원시타입은 가장 기초적인 타입으로, 여기에서는 원시타입과 더블어, 범용적 타입까지 같이 알아보도록 하겠습니다.

 

1) Number, String, Boolen

 

위 세개의 타입은, 우리가 잘 아는 기초적인 타입입니다.

각각 아래의 의미를 가지고 있습니다.

 

타입명 설명 예시
Number 일반적으로 JavaScript 에서 사용하는 숫자입니다. 정수 및 소수점 숫자를 포함합니다. const number = 10
String 단어 그대로 문자열로 이루어진 타입입니다. 일반적으로 '' 으로 감싸서 표현합니다. const string = 'text'
Boolean 참 또는 거짓의 타입이며, true or false 로 표현합니다.  const boolean = true

 

가장 기초적인 타입으로써, JavaScript 에서도 많이 사용해본 타입일 것이라고 생각합니다.

타입에 따라, 사용가능한 method 가 존재하기때문에, TypeScript 는 이러한 타입이 명시가 되면, 사용가능한 method 를 자동으로 처리해줍니다.

이전 포스팅에서 언급한 개념이기도 한 "타입 추론" 기능을 효과적으로 사용하기 위해서는, 사소한 타입이더라도 명시적으로 표현을 해야, 타입 추론 기능의 장점을 잘 활용할 수 있습니다.

 

2) unkown, any

 

이 두개의 타입은 가장 주의해서 사용해야 하는 타입입니다.

특히나, "Any" 의 경우, 사실상 없다고 생각하고 사용해야 합니다.

이유는 아래와 같은 차이가 존재하기 때문입니다.

 

타입명 설명 예시
Any 값에 대해 타입 정보가 없음을 나타냅니다. 이 경우 어떠한 타입의 값, 속성에도 사용이 가능합니다. 하지만 이 타입의 경우, TypeScript 에서 가장 중요한 장점 중 하나인 타입 검사를 무시(생략)함으로, TypeScript 를 사용하는 이유가 없습니다. const any = any
Unknown Any 를 대체해서 사용하지만, 역시 타입 정보가 없음을 나타냅니다. 하지만 Any 와 다르게 안전한 타입 검사를 위해 사용됩니다. 즉, 일반적으로 Return 되는 값을 알지 못하고, 확인이 필요한 경우, unknown 으로 타입검사를 한 뒤, 올바른 타입을 명시할 수 있습니다. const unknown = unknown

즉, 외부 라이브러리, 혹은 API 등을 사용할 때는, 타입을 예상할 수 없거나, 응답이 어떻게 오는지를 확인 후 타입을 지정해야 하는 경우가 발생합니다. 이 때는, Unknwon 을 사용해 Return 되는 값의 타입을 확인 후, 그에 맞게 수정을 해야 하는 작업을 거쳐야 합니다.

Any 와는 다르게, Unknwon 은 타입검사를 진행하는 것이 가장 큰 차이가 있습니다.

 

처음에 타입의 대한 난이도때문에 "Any" 를 난사한다면, Typescript 를 안쓰는게 좋다고 할 수 있습니다. 

 

 

3) Null, undefined, void 

 

이 3개의 타입은, 값이 특정상황일 경우 사용하는 타입입니다.

각각 유사한 의미를 가질수도 있겠지만, 타입별로 정의하는 바가 분명하게 다르기 때문에, 이를 구분해야 합니다.

타입명 설명 예시
Null 값이 없는 타입을 뜻합니다. Undefined 와는 다르며, 리턴한 값이 "null" 이라는 의미로 처리됩니다. 즉, 리턴은 되었지만, 값이 비어있는 타입을 정의할 때 사용합니다. const null = null
Undefined 값이 "할당"되지 않은 변수를 뜻합니다. 
즉 빈 값이 아니라, 할당자체가 되지 않은 변수로, Null 과는 다른 값을 정의합니다.
const undefined = undefined
Void Null 과 undefined 와는 다르게, 반환되는 함수의 값이 없을 때 사용합니다. 주로 Void 의 사용은 console.log 와 같이 함수의 반환값이 없는 경우에 사용됩니다.  const void = console.log('void')

즉 일반적으로 값 자체의 경우, null 이나 undefined 를 사용하지만, 반환의 값이 결정되는 것이 함수이고, 콘솔로그와 같이 값이 반환되지 않는 함수의 결과라면 Void 를 명시해야 합니다. 

이 두가지의 차이를 이해한다면 쉽게 이를 적용할 수 있습니다.

 

4) Symbol

 

객체의 속성을 정의하는 Symbol 은 ES6 부터 도입된 원시 데이터입니다.

이 속성은 주로, 객체 속성의 "Key" 로 사용되는 데이터 타입입니다. 이 타입은 주로 충돌을 방지하기 위해 사용됩니다.

여기서부터는 작성예제와 함께 간단하게 참고해보도록 하겠습니다.

 

타입명 설명 예시
Symbol Symbol 은 객체속성의 키로 사용됩니다.
주로 객체의 충돌을 방지하기 위해 사용하고, 이름이 같은 다른 속성과 식별자가 겹치지 않도록 부여하는 타입입니다.
const symbol1 = Symbol("Symbol")
const symbol2 = Symbol("Symbol")

console.log(symbol1 === symbol2) // false

위와 같이, 각자의 Symbol 은 고유한 값으로서, 객체 속성에 키로 사용됩니다. 각각의 Symbol 은 고유한 값으로 타입이 명시되며, 이를 사용해 속성 이름 충돌을 방지할 수 있습니다. 

이를 추가적으로 사용하면, "Symbol.for(key)" 를 사용하면, 주어진 키와 동일한 Symbol 이 이미 존재한다면, 동일한 Symbol 로 반환하거나, 새로운 Symbol 을 사용할 수도 있습니다.

 

const sharedSymbol1 = Symbol.for("sharedKey");
const sharedSymbol2 = Symbol.for("sharedKey");

console.log(sharedSymbol1 === sharedSymbol2); // true

5) bigint

 

일반적으로 잘 사용할 타입은 아니지만, 정수의 숫자 중 큰 숫자를 지정할 때 사용합니다.

이 bigint 는 ES2020 이후에만 사용이 가능하므로, 이전 버전에서는 사용할 수 없습니다. 

주로 아래와 같이 표현합니다.

const bigint = 10n

 

위의 예시에서는 10의 n승이므로, 일반적인 number 타입에는 담을 수 없는 큰 숫자를 나타냅니다.

 

 

3. 유니언 타입(Union-Type)

 

때때로 타입은 Number 혹은 String 과 같이, 상황에 따라서 다른 값을 반환하는 상황이 발생할 수 있습니다. 

이러한 경우 사용하는 타입이 유니언타입입니다. 유니언 타입은 타입을 2개이상을 지정할 수 있습니다.

즉 개수의 한계는 없지만, 이는 논리적으로 코드의 가독성측면이나, 복잡성 측면에서 좋지 않습니다.

 

이러한 점을 무시하고 극단적으로 표현한다면 아래와 같이도 사용이 가능합니다.

하지만 이렇게 모든 타입을 나열할 경우, Any 나 Unknwon 과 다를바가 없기 때문에, 논리적으로 정해진 유형이 아니라면 사용하지 않는 것이 좋다고 할 수 있습니다.

 

1) 잘못된 예제

type ComplexUnionType = string | number | boolean | null | undefined | object

 

2) 올바른 예제

type ComplexUnionType = string | number

 

위의 타입의 예제를 보면, 잘못된 예제에서는 어떠한 타입이든 유니언타입에 담아 타입추론/검사를 통과하는게 목적이라면, 올바른 예제에서는 논리적으로 예상되는 2개의 선택지에서 사용되었습니다.

잘못된 예제로 작성한 것은, 사실 unknown 을 사용하여, 반환되는 타입을 확인 후 그를 올바르게 업데이트 하는게 좋다고 할 수 있습니다.

 

 

 

4. 타입 작성방법

 

타입을 작성하는 기본 방법은 변수명에 타입을 명시해야 합니다.

각 예제를 아래와 같이 작성할 수 있습니다.

 

const number: number = 1;
const string: string = "string";
const boolean: boolean = true;
const Null: null = null;
const Undefined: undefined = undefined;
const Any: any = null;
const Void: void = console.log("1");
const symbol: symbol = Symbol("1");

추가적으로, 함수역시도 타입을 명시할 수 있습니다.

여기서는 원시타입만을 가지고 함수를 몇가지 예제를 작성해보겠습니다.

 

function number(): number {
  return 10;
}

const num = (): number => {
  return 10;
};

 

각각 선언형 함수, 화살표함수를 사용한 작성 예제입니다.

함수의 타입선언은 매개변수가 들어가는 괄호 " () " 내에 지정해야 합니다.

이를 응용하면, 괄호 내에 매개변수의 타입 역시 지정이 가능합니다 

 

function number(Num1: number, Num2: number): number {
  return Num1 + Num2;
}

const num = (Num2: number, Num3: String): number => {
  return Num2 + Num3;
};

하지만 두번째 애로우함수처럼, 함수의 로직에서, Num2+ Num3 를 더하도록 Return 을 작성했지만, Num3 가 String 과 같은 경우에는 논리적으로 올바르지 않은 작성이므로, 오류를 반환합니다. 이러한 부분 역시 타입스크립트에서 타입을 명시하면, 런타임 이전에 코드의 유효성을 올바르게 검증합니다.

 

위에서 올바르게 동작하도록 변경하려면 Num2 와 Num3 의 타입을 수정하거나, toString().length 와 같이 문자열을 원하는 형태로 변환하여 사용할 수도 있습니다.

 

1) 이제 대표적으로 사용하는 Try & Catch 문을 알아보도록 하겠습니다.

const BlogController = (num1: number, num2: number): number => {
  try {
    const result = num1 + num2;
    return result;
  } catch (e) {
    console.log(e);
    throw new Error(e);
  }
};

 

위의 예제를 본다면, 각 매개변수에 타입을 명시하고, 함수의 반환타입을 명시했습니다.

또한 catch 에서는 console.log 역시 출력을 하지만, Error 를 발생시키므로, 별도의 명시 없이도, 명확한 코드 작성이 가능합니다.

이렇게 작성하면, TypeScript 에서 작성자가 명시한 타입에 맞게 올바른 작성여부를 실행하지 않아도 확인할 수 있습니다.

 

즉, 매개변수에 각각에 인수(인자)로 들어가는 값에 대한 타입, 그리고 난 결과에 대한 타입을 지정하여 사용할 수 있습니다.

일반적으로 Try & catch 문에서 "Throw new Error" 는 return 값으로 보기 때문에, void 와 같은 처리를 생략해도 됩니다.

 

2) Closure 함수

 

클로저 함수는 각각에 타입을 지정하는 형태로 사용이 가능합니다.

예제를 작성해보면 다음과 같습니다.

 

const createNumber = (x: number): ((y: number) => number) => {
  return (y: number): number => {
    return x + y;
  };
};

각각 내부함수, 외부 함수의 변수에 접근해야 하는 클로저 함수의 특성상, 각각의 매개변수, 결과값에 타입을 선언하고, 이 값을 참조하도록 작성이 되야합니다.

따라서 각 매개변수의 인자에 대한 타입과 결과에 대한 타입을 명시하면 됩니다.

 

위의 예제들은 각각 모두 기본적인 원시타입을 사용한 예제입니다.

다음 포스팅에서는 이를 보다 구체화하여 사용할 수 있는 인터페이스에 대해서 다루어보도록 하겠습니다.

 

감사합니다.

반응형

댓글