TypeScript

기본 타입 / readonly / any와 unknown, union

차돌박이츄베릅 2023. 7. 27. 05:58

기본 타입

1) boolean

  • 2가지의 상태에 적합(켜짐/꺼짐, 유효함/유효하지 않음). 조건문이나 비교연산자 등에서 주로 사용.
  • 3가지 이상의 상태를 표현하고 싶은 경우 enum이나 string이 적합.
function isValidPassword(password: string): boolean {
  return password.length >= 8;
}

const password = "q1w2e3r4!";
const valid = isValidPassword(password);

if (valid) {
  console.log("유효한 패스워드입니다!");
} else {
  console.log("유효하지 않은 패스워드입니다!");
}

 

2) number

모든 숫자를 나타냄

  • 정수(소수점이 없는 수): short, int, long
  • 실수(소수점이 있는 수): float, double
  • 2, 8, 16진수까지 표현 가능
function calculateArea(radius: number): number {
  return Math.PI * radius * radius;
}

const radius = 5;
const area = calculateArea(radius);
console.log(`반지름이 ${radius}인 원의 넓이: ${area}`);

 

3) string 

function greet(name: string): string {
  return `안녕, ${name}!`;
}

const name = "Spartan";
const greeting = greet(name);
console.log(greeting);

 

4) 배열

기본 타입에 []를 붙인 형태
...(numbers: number[])...
const testScores: number[] = [90, 85, 78, 92, 88]

function calculateSum(numbers: number[]): number {
  let sum: number = 0;
  for (let i = 0; i < numbers.length; i++) {
    sum += numbers[i];
  }
  return sum;
}

const testScores: number[] = [90, 85, 78, 92, 88];
const sumScore = calculateSum(testScores);
console.log(`점수의 총합: ${sumScore}`);

 

5) 튜플

서로 다른 타입의 원소를 '순서에 맞게' 가질 수 있는 특수한 형태의 배열.
배열은 같은 타입의 원소만 가질 수 있는 데에 반해,
튜플은 '어떤 타입의 원소를 허용'할 것인지 정의해줄 수 있음!

const person: [string, number, boolean] = ['Spartan', 25, false];
const person2: [string, number, boolean] = [25, 'Spartan', false]; // 오류!

ㄴ정의한 갯수보다 더 저장할 수 있으나 좋은 선택은 아님! 정의된 갯수만큼 순서에 맞게 저장하는걸 권장
타입스크립트는 규격된 데이터를 명확하게 정의하고 저장하기 위함

 

6) enum

이넘!! 이너뮬레이션?
열거형 데이터 타입.
다양한 상소를 문자열 이름으로 접근하고 사용할 수 있게 하는 타입.

  • 디폴트 숫자 0부터 시작
  • number이나 string타입만 값으로 할당할 수 있음

enum은 '명확하게 관련된 상수 값들을 그룹화'하고자 할때 사용하는게 좋음. 그러나 값의 수가 많지 않고, 그 관계가 뚜렷하지 않다면 사용하지 않는걸 추천.
명확하게 카테고라이징 할 수 있는 것들만 enum화 하는게 좋음 ! ! !

enum UserRole {
  ADMIN = "ADMIN",
  EDITOR = "EDITOR",
  USER = "USER",
}

enum UserLevel {
  NOT_OPERATOR, // 값을 대입하지 않으면 얘는 자연스럽게 0이 되고,
  OPERATOR // 얘는 1이 됨.
}

function checkPermission(userRole: UserRole, userLevel: UserLevel): void {
  if (userLevel === UserLevel.NOT_OPERATOR) {
  // if (userLevel === 0)과 같음. 하드코딩이므로 지양하고, 
  // UserLevel.NOT_OPERATOR과 같이 추출하여 사용하는 방식 권장함
    console.log('당신은 일반 사용자 레벨이에요');
  } else {
    console.log('당신은 운영자 레벨이군요');
  } 

  if (userRole === UserRole.ADMIN) {
    console.log("당신은 어드민이군요");
  } else if (userRole === UserRole.EDITOR) {
    console.log("당신은 에디터에요");
  } else {
    console.log("당신은 사용자군요");
  }
}

const userRole: UserRole = UserRole.EDITOR;
const userLevel: UserLevel = UserLevel.NOT_OPERATOR;
checkPermission(userRole, userLevel);

 

 


readonly

'객체의 속성을 불변'으로 만드는 데 사용

즉, 클래스의 속성이나 인터페이스의 속성을 변경할 수 없게 함.

상수const나 readonly로 불변성이 보장되어야 코드의 안정성을 높일 수 있다!

class Person { // 클래스는 다른 강의에서 자세히 설명해드릴게요!
  readonly name: string;
  readonly age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

const person = new Person('Spartan', 30);

console.log(person.name);  // 출력: 'Spartan'
console.log(person.age);   // 출력: 30

person.name = 'Jane';  // 에러: 'name'은 readonly 속성이므로 다시 할당할 수 없어요!
person.age = 25;       // 에러: 'age'은 readonly 속성이므로 다시 할당할 수 없어요!

 

 

 


any와 unknown, union 타입

가변적인 타입의 데이터를 저장: any보단 unknown 권장.
가변적인 타입을 '정의'할수 있다면 union타입 사용하는게 가장 낫다.

 

1) any

모든 타입의 슈퍼 타입. 즉, 어떤 타입의 값이든 저장할 수 있다.

기본 타입(넘버, 스트링, 이넘, 불린...), 커스텀 타입(객체나 클래스를 만들어서 씀, 인터페이스)등의 타입이 아니라 

어떤 타입이 올 지 모를 때 사용하는 슈퍼(최상위) 타입.

let anything: any;
anything = 5; // 최초에는 숫자를 넣었지만
anything = 'Hello'; // 문자열도 들어가고요
anything = { id: 1, name: 'John' }; // JSON도 들어가네요

 

db
rdb 관계형 데이터 베이스는
보통 들어오는 데이터 포멧이 정해져있음.
그 스키마에 맞춰서 저장이 됨.
noSql은 공통적인 특징은 가변적인 데이터를 다룬다.
데이터의 포맷이 json일수도 있고 문자열 하나일 수도 있고..
이렇게 가변적인 데이터를 다룰 때 타입스크립트에서 any로 사용할 수 있음

any타입은 코드의 안정성과 유지 보수성을 저해할 수 있기 때문에 가급적 사용하지 말기 !

 

2) unknown

any와 비슷한데 더 안전하다.
모든 타입의 값을 저장할 수 있지만, 그 값을 다른 타입의 변수에 할당하려하면

타입 단언을 통해 명시적으로 타입을 확인해야 함.

let unknownValue: unknown = '나는 문자열이지롱!';
console.log(unknownValue); // 나는 문자열이지롱!

let stringValue: string;
stringValue = unknownValue; // 에러 발생! unknownValue가 string임이 보장이 안되기 때문!

stringValue = unknownValue as string;
// unknownValue은 string이라고 명시해주는거.
// ⭐Type Assertion(타입 단언)이라고 함.
// unknown타입의 변수를 다른 곳에서 사용할 땐 타입 단언을 통해 타입 보장을 하여 사용할 수 있음.

console.log(stringValue); // 나는 문자열이지롱!

 

타입 단언(더 명시적이라 추천) 외에 typeof 사용하는 방식도 있음

let unknownValue: unknown = '나는 문자열이지롱!';
let stringValue: string;

if (typeof unknownValue === 'string') {
  stringValue = unknownValue;
  console.log('unknownValue는 문자열이네요~');
} else {
  console.log('unknownValue는 문자열이 아니었습니다~');
}

 

3) union

unknown타입이 재할당 시 타입체크가 되어 비교적 안전함을 보장하긴하나, 재할당이 일어나지 않으면 타입 안전성이 보장 되지 않음. 이럴 땐 union타입 ㄱㄱ
여러 타입 중 하나를 가질 수 있는 변수를 선언할 때 사용!
| 연산자를 사용하여 여러 타입을 결합하여 표현.

type StringOrNumber = string | number; // 원한다면 | boolean 이런식으로 타입 추가가 가능해요!

function processValue(value: StringOrNumber) {
  if (typeof value === 'string') { // value의 타입이 string타입 일 때
    // value는 여기서 string 타입으로 간주됩니다.
    console.log('String value:', value);
  } else if (typeof value === 'number') {
    // value는 여기서 number 타입으로 간주되구요!
    console.log('Number value:', value);
  }
}

processValue('Hello');
processValue(42);



=> 타입스크립트에서 여러 타입을 하나의 변수로 해결하겠다는 생각은 가급적 지양