타입스크립트 기본 타입
- 위는 타입 트리라고도 하며, 부모-자식 관계이다.
1. 원시타입
- 하나의 값만 저장하는 타입
1. number
타입
const num1: number = 123;
// 위처럼 ": (타입)"을 type annotation(타입 주석)이라고 한다.
// number: 숫자를 모두 포함하는 타입
let num1: number = 123; // 양의 정수
let num2: number = 123; // 음의 정수
let num3: number = 0.123; // 양의 소수
let num4: number = -0.123; // 음의 소수
let num5: number = Infinity; // 무한대
let num6: number = -Infinity; // -무한대
let num7: number = NaN; // 특수한 NaN 데이터도 number 타입
2. string
타입
// string
let str1: string = "hello";
let str2: string = "hello";
let str3: string = `hello`;
let str4: string = `hello ${num1}`;
// str1 = 123; // ❌
3. boolean
타입
// boolean
let bool1: boolean = true;
let bool2: boolean = false;
4. null
타입
// null
let null1: null = null; // null만 올 수 있다.
5. undefined
타입
// undefined
let undef1: undefined = undefined; // undefined만 올 수 있다.
💡 변수에 지정한 타입 외에 (임시로) null을 넣고 싶으면 아래처럼 컴파일러옵션을 설정한다.
// tsconfig.json
"compilerOptions": {
"strictNullChecks": false,
}
// index.ts
let numA: number = null; // ⭕
6. ⭐ literal
타입
let numA: 10 = 10; // ⭕
numA = 12; // ❌
let boolA: true = true; // ⭕
boolA = false; // ❌
- 그 값 자체를 마치 타입처럼 사용할 수 있다.
2. 배열과 튜플
배열
배열 타입 선언 방식
type[]
(ex) number[], string[] 등)제네릭 Array<type>
(ex) Array<number>, Array<string> 등)
// 배열
let numArr: number[] = [1, 2, 3]; // number형 데이터를 원소로 갖는 배열
let strArr: string[] = ["hello", "typescript"]; // string형 데이터를 원소로 갖는 배열
// 또다른 방법으로 아래처럼 제네릭 문법을 사용할 수 있다.
let boolArr: Array<boolean> = [true, false, true];
배열에 들어가는 요소들의 타입이 다양한 경우
union type
이용 ex)let multiArr: (string | number)[] = [1, "alice"];
다차원 배열인 경우
let doubleArr: number[][] = [
[1, 2],
[3, 4],
[5, 6],
]; // number형 원소를 담는 배열을 저장하는 배열
튜플 - (JS에는 없는 타입이다)
- 길이와 타입이 고정된 배열
let tuple1: [number, number] = [1, 2];
let tuple2: [string, number, boolean] = ["alice", 25, true];
tuple2.push(3); // ⭕ // push나 pop을 해도 에러가 발생하지 않는다.
console.log(tuple2); // [ 'alice', 25, true, 3 ]
// 배열 메소드를 사용할 땐 tuple의 길이 제한이 발동하지 않는다. 따라서 튜플 타입에 배열 메소드를 사용할 땐 각별히 주의를 기울여야 한다.
⭐ 배열 메소드를 쓸 땐 tuple의 개수 제한이 발동하지 않기 때문에 비정상 동작한다. 따라서 각별히 주의할 것!
3. 객체
let user = {
id: 1,
name: 'alice'
}
위와 같은 객체의 타입은 리터럴 타입으로 지정해야 한다.
👇
let user: {
id: number;
name: string;
} = {
id: 1,
name: 'alice'
}
- 객체 리터럴 타입이라고 한다.
- 이런 식으로 그 객체의 구조를 기준으로 타입을 정의하는 것을 구조적 타입 시스템이라고 한다.
💡 선택적 프로퍼티(optional property)
- 타입 이름 뒤에
?
를 붙인다.
let user: {
id?: number; // 👈 id 프로퍼티가 있어도 되고, 없어도 된다. 대신 존재한다면 number형 데이터가 와야 함
name: string;
} = {
id: 1,
name: 'alice'
}
💡 객체 프로퍼티의 값을 수정하지 못하게 하기
- 타입 이름 앞에
readonly
키워드를 붙여 읽기전용 프로퍼티로 만든다.
let config: {
readonly apiKey: string;
} = {
apiKey: "MY_API_KEY"
}
config.apiKey = "hacked"; // ❌ 읽기 전용 프로퍼티는 수정할 수 없다.
💡 명목적 타입 시스템 vs. 구조적 타입 시스템
명목적 타입 시스템
- ‘이름’을 기준으로 타입을 정의하는 것 ex) C, Java 언어
구조적 타입 시스템
- 그 객체를 이루는 ‘구조’를 기준으로 타입을 정의하는 것
- 타입스크립트는 구조적 타입 시스템을 사용한다.
4. 타입 별칭 & 인덱스 시그니처
타입 별칭(type alias)
type User = { // User라는 타입 별칭 선언
id: number;
name: string;
nickname: string;
birth: string;
bio: string;
};
let user: User = {
id: 1,
name: "김철수",
nickname: "alice",
birth: "1999.01.30",
bio: "안녕하세요",
};
let user2: User = {
id: 2,
name: "홍길동",
nickname: "winterlood",
birth: "1997.01.07",
bio: "안녕하세요",
};
- 타입 별칭을 사용하면 똑같은 객체 리터럴 타입을 갖는 변수를 선언할 때 타입 선언 중복을 줄일 수 있다.
💡 타입 별칭은 동일한 스코프에 중복된 이름으로 선언할 수 없다.
type User = {
id: number;
name: string;
nickname: string;
birth: string;
bio: string;
location: string;
};
type User = {...} // ❌
인덱스 시그니처
- 객체에 계속 같은 타입의 프로퍼티를 추가할 때마다 위와 같이 객체 리터럴 타입을 추가해야 한다는 불편함이 있다.
- 인덱스 시그니처를 이용해서 프로퍼티의 타입만 지정하면, 해당 타입에 맞는 프로퍼티가 몇 개가 들어와도 상관없다.
type CountryCodes = {
[key: string]: string; // 👈 인덱스 시그니처
};
let countryCodes: CountryCodes = {
Korea: "ko",
UnitedState: "us",
UnitedKingdom: "uk",
// (... 약 100개의 국가)
Brazil : 'bz'
};
let countryCodes_ver2: CountryCodes = {}; // ⭕
💡 해당 인덱스 시그니처를 타입으로 갖는 객체는, 빈 객체여도 에러가 나지 않는다. (인덱스 시그니처는 해당 타입에 위반하지 않으면 따로 에러가 발동하지 않기 때문에 빈 객체는 타입 검사 자체가 이루어지지 않음)
5. 열거형 타입 - enum
- 여러가지 값들에 각각 이름을 부여해 열거해두고 사용하는 타입
- TS에서만 제공되는 타입
enum
타입은 왜 필요할까?- 아래처럼 숫자를 이용해 역할을 분류할 때, 헷갈리지 않도록 하기 위해 활용할 수 있다.
숫자 열거형
enum Role { // 👈 enum type
ADMIN = 0,
USER = 1,
GUEST = 2,
}
const user1 = {
name: "앨리스",
role: Role.ADMIN, //관리자
};
const user2 = {
name: "홍길동",
role: Role.USER, // 회원
};
const user3 = {
name: "아무개",
role: Role.GUEST, // 게스트
};
console.log(user1, user2, user3)
💡 enum에 value를 설정해주지 않으면 0부터 시작하고, 만약 처음에 값을 설정해주면 그 다음으로 1씩 증가한다.
enum Role {
ADMIN, // 0
USER, // 1
GUEST, // 2
}
enum Role {
ADMIN = 10,
USER, // 11
GUEST, // 12
}
문자열 열거형
- enum의 멤버로 문자열 값도 할당할 수 있다
enum Language {
korean = "ko",
english = "en",
}
const user1= {
name: "앨리스",
language: Language.korean,// "ko"
};
- 문자열 enum을 사용하면 오타 실수를 줄일 수 있음
💡 enum은 컴파일될 때 다른 타입들처럼 사라지지 않고, 자바스크립트 객체로 변환되어 남는다. 따라서 계속해서 이 값을 이용할 수 있는 것이다.
6. any
타입
- 변수 타입을 확실히 모를 때 사용한다.
- 타입 상관없이 아무거나 오게 할 수 있을 때 지정한다.
let anyVar: any = 10;
anyVar = "alice"; // ⭕
- 반대로 모든 타입의 변수에 any 타입의 값을 할당할 수 있다.
let anyVar: any = 10;
let num: number = 10;
num = anyVar; // 에러가 나지 않는다.
- 이외에도 다양한 타입의 메소드도 마음대로 사용해도 문제가 되지 않는다.
- 하지만 any는 이후 런타임에서 에러가 발생할 수 있다는 단점이 있고, 또한 일종의 치트키이기 때문에 당장은 에러 해결을 할 수 있어도 타입스크립트 사용 목적을 잃어버림 ⇒ 권장 X
7. unknown
타입
- any와 비슷하게 어떤 타입의 데이터가 와도 가능하다.
let unknownVar: unknown;
unknownVar = "";
unknownVar = 1;
unknownVar = () => {};
- 하지만 any와 달리 unknown 형식의 데이터를 다른 타입의 변수에 할당할 수 없고, 어떠한 연산이나 메소드도 전혀 사용할 수 없다.
let num: number = 10;
let unknownVar: unknown;
unknownVar = "";
unknownVar = 1;
unknownVar = () => {};
num = unknownVar; // ❌
unknownVar * 2 // ❌
정리)
any
타입은 타입 검사를 받지 않는 타입이므로 모든 타입스크립트의 문법과 규칙으로부터 자유롭지만 그만큼 위험한 타입이다. 따라서 any
타입을 많이 사용하면 많은 부분에서 타입 검사가 제대로 이루어지지 않기에 위험한 코드가 생산되고, 궁극적으로 타입스크립트를 사용할 이유가 없다.
unknown
타입은 모든 값을 할당받을 수 있게 되지만, 반대로 unknown
타입의 값은 그 어떤 타입의 변수에도 할당할 수 없고, 모든 연산에 참가할 수 없다. 쉽게 정리하면 오직 값을 저장하는 행위밖에 할 수 없음
8. void
타입
- 아무것도 반환하지 않는 함수의 타입을 정의할 때 사용
- 변수에도 void 타입으로 지정할 수 있고, 이 땐 undefined 값만 허용된다(단,
strictNullChecks
옵션을 해제(false)하면 null도 허용) - null이나 undefined로 함수 타입을 지정하면 무조건 해당 타입을 return하는 구문을 넣어야 한다. return문 자체가 없는 함수를 정의하고 싶다면 void로 설정한다.
function func1(): undefined {
console.log("hello");
return undefined; // 꼭 undefined를 반환하는 return문을 넣어야 한다.
}
function func2(): null {
console.log("hello");
return null; // 꼭 null을 반환하는 return문을 넣어야 한다.
}
function func3(): void {
console.log("hello");
}
9. never
타입
- 존재하지 않는, 불가능한 타입 = 정상적으로 종료되지 않아서, 함수가 return된다는 것 자체가 모순이다 할 때 이 타입을 사용한다.
ex 1) 무한루프에 빠진 함수
function func1(): never {
while (true) {}
}
ex 2) 에러를 throw하는 함수: 실행되면 바로 프로그램이 종료되므로 never 타입이 적합
function func2(): never {
throw new Error();
}
💡 never 타입의 변수에 어떠한 값도 저장할 수 없다.
Reference
한 입 크기로 잘라먹는 타입스크립트 - 인프런 | 강의
문법을 넘어 동작 원리와 개념 이해까지 배워도 배워도 헷갈리는 타입스크립트 이제 제대로 배워보세요! 여러분을 타입스크립트 마법사🧙🏻♀️로 만들어드립니다., - 강의 소개 | 인프런
www.inflearn.com
'Front-end > TypeScript' 카테고리의 다른 글
파일 저장 시 eslint 동작하기 설정 (0) | 2023.08.07 |
---|---|
[TypeScript] 컴파일러 기본 옵션 설정하기 (0) | 2023.06.17 |