조아마시

쓸모 있는 상세페이지 만들기

웹개발/typescript

[타입스크립트] 문자열 타입

joamashi 2024. 8. 30. 22:00

타입스크립트에서 문자열 타입은 우리가 일상적으로 사용하는 문자들의 집합을 나타냅니다. 즉, "Hello, world!", "안녕하세요", "123" 등과 같이 따옴표("") 안에 들어 있는 모든 글자들이 문자열입니다.

왜 문자열 타입이 중요할까요?

  • 코드 가독성 향상: 변수의 타입을 명확히 함으로써 코드를 더 쉽게 이해하고 유지 관리할 수 있습니다.
  • 오류 예방: 컴파일 시에 타입 오류를 미리 감지하여 실행 중 오류를 줄일 수 있습니다.
  • 자동 완성 및 리팩토링 지원: IDE의 강력한 기능을 활용하여 개발 생산성을 높일 수 있습니다.

다양한 문자열 타입 예시

// 기본 문자열
let greeting: string = "Hello, TypeScript!";

// 빈 문자열
let emptyString: string = "";

// 숫자를 포함한 문자열
let numberString: string = "42";

// 특수 문자 포함 문자열
let specialChars: string = "Hello, world! ";

// 템플릿 문자열 (ES6+)
let name: string = "Alice";
let age: number = 30;
let templateString: string = `Hello, my name is ${name} and I am ${age} years old.`;

템플릿 문자열은 변수나 표현식을 문자열 안에 직접 삽입할 수 있는 편리한 기능입니다. 위 예시처럼 ` `(백틱)으로 감싸고, 변수나 표현식을 ${}로 감싸면 됩니다.

문자열 관련 유용한 메서드

  • length: 문자열의 길이를 반환합니다.
  • toUpperCase(), toLowerCase(): 문자열을 대문자 또는 소문자로 변환합니다.
  • slice(): 문자열의 일부를 추출합니다.
  • indexOf(): 특정 문자열이 처음으로 나타나는 인덱스를 반환합니다.
  • replace(): 문자열의 특정 부분을 다른 문자열로 바꿉니다.
  • split(): 문자열을 특정 기준으로 나누어 배열로 만듭니다.
let message: string = "Hello, TypeScript!";
let uppercaseMessage: string = message.toUpperCase(); // HELLO, TYPESCRIPT!
let firstWord: string = message.slice(0, 5); // Hello

문자열 타입 활용 예시

  • 사용자 입력 값 검증: 사용자가 입력한 값이 문자열인지 확인하고, 필요한 형식에 맞는지 검사합니다.
  • API 통신: 서버로부터 받은 JSON 데이터에서 문자열 형태의 값을 추출하여 사용합니다.
  • DOM 조작: 웹 페이지의 HTML 요소의 내용을 변경하거나, 새로운 요소를 생성할 때 문자열을 사용합니다.

다양한 방식으로 표현하기

타입스크립트에서 문자열 타입을 선언하는 가장 기본적인 방법은 string 키워드를 사용하는 것입니다. 하지만 이 외에도 더욱 세밀하게 문자열 타입을 지정하고 관리할 수 있는 다양한 방법들이 있습니다.

1. 리터럴 타입 (Literal Type)

특정 문자열 값만 허용하고 싶을 때 사용합니다.

let direction: 'up' | 'down' | 'left' | 'right' = 'up';

위 예시에서는 direction 변수에 'up', 'down', 'left', 'right' 중 하나의 값만 할당할 수 있습니다.

2. 유니온 타입 (Union Type)

여러 가지 타입 중 하나를 가질 수 있도록 허용합니다. 문자열뿐만 아니라 다른 타입과의 조합도 가능합니다.

let value: string | number = 'hello';
value = 42;

3. 인터페이스 (Interface)

복잡한 객체의 구조를 정의할 때 사용하며, 문자열 타입의 프로퍼티를 가질 수 있습니다.

interface Person {
  name: string;
  age: number;
}

let person: Person = {
  name: 'Alice',
  age: 30
};

4. 타입 별칭 (Type Alias)

복잡한 타입에 간단한 이름을 부여하여 코드를 더욱 명확하게 만들 수 있습니다.

type Greeting = string;
let message: Greeting = 'Hello, world!';

5. 템플릿 문자열 타입 (Template Literal Type)

특정 패턴을 가진 문자열을 표현할 때 유용합니다.

type Email = `${string}@${string}.com`;
let email: Email = 'alice@example.com';

6. null, undefined 허용 여부

문자열에 null 또는 undefined 값을 허용할지 여부를 명시할 수 있습니다.

let nullableString: string | null = null;
let undefinedString: string | undefined = undefined;

7. readonly 키워드

문자열 값을 변경할 수 없도록 만들 때 사용합니다.

interface User {
  readonly name: string;
}

선택해야 할 방법은?

  • 정확한 값 제한: 리터럴 타입
  • 여러 타입 허용: 유니온 타입
  • 복잡한 객체: 인터페이스
  • 간단한 타입 별칭: 타입 별칭
  • 패턴 기반: 템플릿 문자열 타입
  • null, undefined 허용: null, undefined 키워드
  • 값 변경 방지: readonly 키워드

어떤 방법을 선택할지는 코드의 특성과 요구사항에 따라 달라집니다.

// 사용자 입력 값 검증
function validateInput(input: string): boolean {
  return input.length > 0 && input.includes('@'); // 이메일 형식 검사
}

// API 응답 처리
interface ApiResponse {
  message: string;
  data: {
    id: number;
    name: string;
  };
}

// DOM 조작
const element = document.getElementById('myElement') as HTMLInputElement;
element.value = 'Hello';

다양한 방식으로 표현하기 (심화)

이전에 문자열 타입 선언에 대해 폭넓게 다루었는데요, 이번에는 좀 더 심층적으로 다양한 방식과 활용법에 대해 알아보겠습니다.

1. enum 타입 활용

  • 특정 값의 집합 표현: 특정 값들만 허용되는 경우 enum을 사용하여 코드 가독성을 높일 수 있습니다.
enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT'
}

let direction: Direction = Direction.Up;

2. 인덱스 시그니처

  • 동적 프로퍼티: 객체의 프로퍼티 이름이 동적으로 결정될 때 사용합니다.
interface StringMap {
  [key: string]: string;
}

let myMap: StringMap = {
  name: 'Alice',
  age: '30' // 숫자를 문자열로 변환하여 저장
};

3. Mapped Type

  • 기존 타입 변형: 기존 타입을 기반으로 새로운 타입을 만들 때 유용합니다.
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

interface User {
  name: string;
  age: number;
}

type ReadonlyUser = Readonly<User>;

4. Conditional Types

  • 조건에 따른 타입: 특정 조건에 따라 다른 타입을 할당할 수 있습니다.
type IfEquals<X, Y> = (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false;

type IsString<T> = IfEquals<T, string>;

5. infer 키워드

  • 제네릭 타입 추론: 함수의 인자나 반환값의 타입을 자동으로 추론합니다.
type ReturnType<T> = T extends (...args: any[]) => infer U ? U : never;

6. keyof 키워드

  • 객체의 키 타입: 객체의 모든 키를 나타내는 타입을 생성합니다.
interface User {
  name: string;
  age: number;
}

type UserKeys = keyof User; // 'name' | 'age'

7. typeof 키워드

  • 변수의 타입: 변수의 실제 타입을 가져옵니다.
let message: string = 'Hello';
type MessageType = typeof message; // string

8. indexed access types

  • 인덱스 시그니처의 타입: 인덱스 시그니처를 통해 특정 프로퍼티의 타입을 추론합니다.
type UserMap = { [key: string]: { name: string; age: number } };
type UserName = UserMap[string]['name']; // string

9. mapped type 조합

  • 복잡한 타입 생성: 여러 mapped type을 조합하여 다양한 타입을 만들 수 있습니다.
type Partial<T> = { [P in keyof T]?: T[P] };

10. 조건부 타입과 mapped type 조합

  • 더욱 복잡한 로직: 조건부 타입과 mapped type을 함께 사용하여 강력한 타입 시스템을 구축할 수 있습니다.

언제 어떤 방식을 사용해야 할까요?

  • 특정 값 제한: enum, 리터럴 타입
  • 동적 프로퍼티: 인덱스 시그니처
  • 기존 타입 변형: mapped type
  • 조건에 따른 타입: 조건부 타입
  • 제네릭 타입 추론: infer 키워드
  • 객체의 키 타입: keyof 키워드
  • 변수의 타입: typeof 키워드
  • 인덱스 시그니처의 타입: indexed access types
  • 복잡한 타입 생성: mapped type 조합
728x90