정해진
string
값을 가진 것
/*
const: 변하지 않는 값 선언
let: 변할 수 있는 값 선언 */
const userName1 = "Bob"; // 👈 문자열 리터럴 타입
let userName2 = "Tom";
/*
각 변수에 hover시 나오는 타입:
userName1 - "Bob" (string이지만, 변할 수 없음 -> "Bob" 외 불가) 👈 문자열 리터럴 타입인 이유
userName2 - string ("Tom"이지만, 바꿀 수 있음 -> 더 넓은 개념의 string) */
userName2 = 3;
/*
[에러 발생]
- 이유: 최초 할당 값이 string (타입 명시 안했어도) */
// [해결 방법] 명시적으로 재작성 (숫자도 넣으려면)
let userName2 : string | number = "Tom";
type
으로 이넘과 비슷한 형태 제작 가능type Job = "police" | "developer" | "teacher";
interface User {
name: string;
job: Job;
}
const user: User = {
name: "Bob",
job: "developer" // Job에서 선언한 string만 사용 가능. 그 외 입력 시, 에러 발생.
}
interface HighSchoolStudent {
name: string;
grade: 1 | 2 | 3; // 학년은 1,2,3만 입력 가능하면 됨.
}
타입 의미: A이거나 B이다 ( JS의 OR 연산자(
||
)와 같음 )
연산자 (|
)를 이용 → 타입을 여러 개 연결하는 방식
function logText(text: string | number) {
// ...
}
// text(함수의 파라미터)에는 문자열 or 숫자 타입 가능
any
사용 시 → JS로 작성하는 것처럼 동작
유니온 타입 사용 시 → TS의 이점을 살리면서 코딩 가능
예시 코드
// any를 사용하는 경우
function getAge(age: any) {
age.toFixed(); // 에러 발생. 숫자 관련 API를 작성 시, 코드 자동 완성 x (이유: age의 타입이 any로 추론)
return age;
}
// 유니온 타입을 사용하는 경우
function getAge(age: number | string) {
if (typeof age === 'number') {
age.toFixed(); // 정상 동작. 숫자 관련 API를 쉽게 자동완성 가능 (이유: age의 타입이 `number`로 추론)
return age;
}
if (typeof age === 'string') {
return age;
}
return new TypeError('age must be number or string');
}
인터페이스와 같은 타입을 다룰 때, 논리적 사고(유니온 타입은 OR, 인터섹션은 AND)를 주의
타입들에 공통적으로 들어있는 속성에만 접근 가능
별도의 타입 가드(Type Guard)를 이용하여 타입의 범위를 좁히지 않는 이상
이유
TS 관점에서는 어느 타입이 올지 알 수 x → 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론
예시
interface Person {
name: string;
age: number;
}
interface Developer {
name: string;
skill: string;
}
function introduce(someone: Person | Developer) {
someone.name; // O 정상 동작
someone.age; // X 타입 오류
someone.skill; // X 타입 오류
}
/*
해설 :
`introduce()` 함수의 파라미터 타입을 두 인터페이스들의 유니온 타입으로 정의함.
→ 유니온 타입은 A도, B도 될 수 있는 타입이라고 생각 가능
→ 인터페이스들이 제공하는 속성들인 `age`나 `skill`를 사용 가능할 것이라고 생각 가능
→ TS 관점에서는 `introduce()` 함수를 호출하는 시점에 둘 중 어느 타입이 올지 알 수 x
→ 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론
*/
const capt: Person = { name: 'capt', age: 100 };
introduce(capt); // 만약 `introduce` 함수 안에서 `someone.skill` 속성을 접근하고 있으면 함수에서 오류 발생
const tony: Developer = { name: 'tony', skill: 'iron making' };
introduce(tony); // 만약 `introduce` 함수 안에서 `someone.age` 속성을 접근하고 있으면 함수에서 오류 발생
// name(두 타입의 공통 속성)만 접근 가능
function introduce(someone: Person | Developer) {
console.log(someone.name); // O 정상 동작
}
동일한 속성의 타입을 다르게 해서 구분 가능
검사 항목 수에 따른 추천 조건문 (가독성 용이)
if
문switch
문▼ 예시 코드
interface Car {
name: "car";
color: string;
start(): void;
}
interface Mobile {
name: "mobile";
color: string;
call(): void;
}
function getGift(gift: Car | Mobile) {
console.log(gift.color); // [문제 無] 이유: 둘 다 색상 보유.
gift.start(); // [에러 발생]
}
/*
에러
- 메세지: Car 또는 Mobile 에는 start가 없다. (즉, Car만 start 함수 보유)
- 해결 방법: start 사용 전, Car인지 먼저 확인 */
function getGift(gift: Car | Mobile) {
console.log(gift.color);
// [해결] 식별 가능한 Union Type 사용
if (gift.name === 'car'){
gift.start(); // gift에 호버 시, Car로 파악함.
} else {
gift.call(); // gift에 호버 시, Mobile로 파악함.
}
}
/*
각 인터페이스의 name 속성 타입
- Car: "car" 타입
- Mobile: "mobile" 타입 (string 타입 아님.) */
여러 개의 타입을 하나로 합쳐주는 역할. (AND를 의미)
연산자(&
) 이용
모든 속성 기입 필수
→ 다 적을 때까지 에러 안 사라짐.
→ 공통된 속성은 1번만 선언.
interface Car {
name: string;
start(): void;
}
interface Toy {
name: string;
color: string;
price: number;
}
const toyCar: Toy & Car = {
name: "타요", // 한 번만 선언
start(){},
color: "red",
price: 1000,
}
type
) interface Person {
name: string;
age: number;
}
interface Developer {
name: string;
skill: number;
}
type Capt = Person & Developer;
// Person 인터페이스의 타입 정의와 Developer 인터페이스의 타입 정의를 합친 후(& 연산자 이용) Capt 타입에 할당
// Capt의 타입
{
name: string;
age: number;
skill: string;
}
참고