티스토리 뷰
타입스크립트의 기본 타입
기본 타입이란 타입스크립트가 자체적으로 제공하는 타입을 말한다.
지금부터 자바스크립트의 타입에 대해 자세하게 살펴보자.
1. 타입 정의하는 방법
type annotation(타입 주석)
변수명 오른쪽에 :
을 붙여서 변수의 타입을 명시하는 방법이다.
// ex : number 타입의 변수 num1
let num1: number = 123;
2. 타입 종류
💨 원시타입(number, string, boolean, null, undefined)과 리터럴 타입
원시 타입(Primitive Type)은 동시에 한개의 값만 저장할 수 있는 타입을 말한다.일반적인 자바스크립트 원시 타입과 동일하다.
타입스크립트는 여기서 변수명 뒤에 타입만 명시(타입 주석, 타입 어노테이션)하면 된다.
// number
let num1: number = 123;
let num2: number = -1324;
let num3: number = 0.123;
let num4: number = -0.123;
let num5: number = Infinity;
let num6: number = -Infinity;
let num7: number = NaN;
// string
let str1: string = "hello";
let str2: string = `hello`;
let str3: string = `hello ${num1}`;
// boolean
let b1: boolean = true;
let b2: boolean = false;
// null
let n1: null = null;
// undefined
let und1: undefined = undefined;
타입스크립트에서는 딱 하나의 값만 포함하는 타입도 존재한다. 이를 리터럴 타입이라고 한다.
// 리터럴 타입 : 값 자체가 타입이 되는 타입
let numA: 10 = 10;
// numA = 12 // 불가능
변수에 임시로 null 값을 넣는 방법
null 타입이 아닌 변수에도 임시로 null 값을 넣는 방법은 다음과 같다.
1. tsconfig.json
파일 수정
아래와 같이 tsconfig.json
파일에서 strcitNullChecks(엄격한 null 검사) 옵션을 false로 설정한다.
{
"include": ["src"],
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"outDir": "dist",
"strict": true,
"strictNullChecks": false,
"moduleDetection": "force"
},
"ts-node": {
"esm": true
}
}
2. null 타입 할당
이제 다음과 같이 null 타입이 아닌 변수에도 null 값을 할당할 수 있다.
let numA: number = null; // 가능
strict 옵션은 strictNullChecks 옵션의 상위 옵션이다. 따라서 strict 옵션이 true로 되어있으면 strictNullChecks 옵션도 자동으로 true로 지정된다.
참고로 이 옵션은 안전한 타입스크립트 코드를 작성하는 측면에서는 큰 도움이 되지 않으므로 true로 설정하거나 아예 옵션 설정을 지우는 것이 좋다.
💨 배열과 튜플
(1) 기본 배열
타입스크립트에서 배열을 정의하는 방법은 크게 두 가지가 있다.
배열요소타입[]
사용Array<배열요소타입>
사용 => 제네릭
// 방법 1
let numArr: number[] = [1, 2, 3];
let strArr: string[] = ["hello", "nice", "to meet you"];
// 방법 2 : 제네릭
let boolArr: Array<boolean> = [true, false, true];
(2) 다양한 타입으로 구성된 배열
만약 여러 타입으로 구성된 배열이라면?
union 타입으로 정의한다.
let nultiArr: (string | number)[] = [1, "hello"];
(3) 다차원 배열
[]을 연달아 작성하여 정의한다.
// 2차원 배열 정의
let doubleArr: number[][] = [
[1, 2, 3],
[4, 5],
];
(4) 튜플
튜플은 타입스크립트에서만 제공되는 타입으로, 일반적으로 길이와 타입이 고정된 배열 을 말한다.
타입스크립트의 튜플은 컴파일시 자바스크립트 배열로 변환되기 때문에 타입스크립트에서는 튜플의 길이를 완전히 제한하기는 어렵다.
let tup1: [number, number] = [1, 2];
let tup2: [number, string, boolean] = [1, "2", true];
// 튜플 길이 변경 가능
tup1.push(2); // 가능
tup1.pop(); // 가능
튜플은 주로 인덱스의 순서와 위치를 강제하고 싶을 때 사용된다.
const users: [string, number][] = [
["김아무개", 1],
["이아무개", 2],
["박아무개", 3],
["최아무개", 4],
// [5, "장아무개"] 불가능
];
💨 객체
타입스크립트는 기본적으로 구조적 타입시스템을 가지고 있다.
구조적 타입시스템은 프로퍼티를 기준으로 타입을 정의하는 것을 말한다(property based type system).
참고로 구조적 타입시스템의 반대는 명목적 타입 시스템이라고 한다(자바, c 등).
타입스크립트에서 객체 타입은 어떻게 정의할까?
위에서 살펴본 다른 타입들처럼 변수명 뒤에 :object를 붙인다고 생각하기 쉽다.
아래의 코드가 그 예시다.
// object
let user1: object = {
id: 1,
name: "홍길동",
};
그러나 이렇게 object으로 타입을 명시했을 때, user.id
처럼 객체의 프로퍼티에 따로 접근할 수 없다. 즉, 이런 선언방식은 이 변수가 "객체"다 라는 정보만 제공할 뿐, 객체 안의 프로퍼티에 대한 정보는 어떠한 것도 얻을 수 없다.
객체 리터럴 타입
따라서 객체 타입은 객체 리터럴 타입으로 정의한다. 변수의 타입을 객체 리터럴 타입으로 정의하면 타입 내에 정의되어있는 프로퍼티에 이상 없이 접근할 수 있게 된다.
// 객체 리터럴 타입
let user2: {
id: number;
name: string;
} = {
id: 1,
name: "홍길동",
};
let dog: {
name: string;
color: string;
} = {
name: "강아지",
color: "brwon",
};
선택적 프로퍼티(Optional Property)
만약 특정 프로퍼티 값이 필요할 수도, 필요 없을수도 있다면, 타입 정의시 변수명 뒤에 ?
을 붙인다.
// id값은 없어도 될 때
let user3: {
id?: number; // 선택적 프로퍼티
name: string;
} = {
id: 1,
name: "김아무개",
};
user3 = {
name: "홍길동",
};
읽기 전용 프로퍼티
특정 프로퍼티의 수정을 금지하고 싶다면 타입 정의시 readonly
키워드를 변수 왼쪽에 붙인다.
// readonly 사용
let config: {
readonly apiKey: string;
} = {
apiKey: "MY API KEY",
};
config.apiKey = "NEW KEY"; // 불가능
💨 Enum(열거형) 타입
enum 타입은 여러가지 값들에 각각 이름을 부여해 열거해두고 사용하는 타입을 말한다.
튜플과 마찬가지로 자바스크립트에는 없는 타입이지만, 컴파일 이후에도 이 타입은 사라지지 않는다. 컴파일 시 타입스크립트의 enum 타입은 자바스크립트의 객체타입으로 변환된다.
// 숫자형
enum Role {
ADMINT = 0,
USER = 1,
GUEST = 2,
}
// 문자열
enum Language {
korean = "ko",
english = "en",
}
const user1 = {
name: "홍길동",
role: Role.ADMINT,
};
const user2 = {
name: "홍길똥",
role: Role.USER,
};
const user3 = {
name: "홍길독",
role: Role.GUEST,
language: Language.english,
};
console.log(user1, user2, user3);
// { name: '홍길동', role: 0 } { name: '홍길똥', role: 1 } { name: '홍길독', role: 2 }
숫자형 enum의 경우 숫자를 따로 할당해주지 않아도 자동으로 0,1,2,,, 순서대로 값을 할당해준다.
혹은 시작하는 숫자를 직접 지정해줄 수 있다. 이때는 맨 처음 시작값에만 그 값을 표기한다.
💨 Any와 Unknown
(1) Any
any 타입은 특정 변수의 타입을 확실하게 알 수 없을 때 사용한다. any 타입으로 지정된 변수에는 어떤 타입의 값이든지 넣을 수 있다. 자바스크립트의 변수를 쓰는 것과 동일하게 작동되는 것이다.
let anyVar: any = 10;
anyVar = "hello"; // any 타입은 이런 것도 가능
anyVar = () => {};
anyVar = {};
심지어 다른 타입의 변수에도 any 타입 변수를 집어넣는 것이 가능하다.
var num: number = 10;
num = anyVar;
외로도 any 타입 변수는 다른 타입의 메서드(ex. string 타입의 toUpperCase())를 따로 활용할 수 있다.
그러나 any 타입은 타입 검사를 런타임에 수행하므로 타입스크립트의 이점을 활용하지 않는 방식이기 때문에 사용을 지양하는 것이 좋다.
(2) Unknown
unknown 타입은 any타입과 비슷하게 어떤 타입이든지 넣을 수 있는 타입을 말한다.
// unknown
let unknownVar: unknown;
unknownVar = "";
unknownVar = 1234;
unknownVar = {};
unknownVar = () => {};
any와의 차이점은 unkown은 다른 타입의 변수에 집어넣을 수 없다는 것이다. 또한 다른 타입의 메서드를 따로 활용할 수도 없다.
var num: number = 10;
num = unknownVar; // 이런 할당 불가능
만약 다른 타입을 할당하고자 한다면, 타입 정제
과정을 거쳐야 한다.
// 타입 정제
if (typeof unknownVar === "number") {
num = unknownVar; // unknown타입은 타입 정제 후 할당 가능
}
unknown은 런타임 에러를 일으키는 any 타입보다는 안전한 방식이다.
💨 Void와 Never
(1) void
void는 아무것도 없음을 의미하는 타입이다.
아래의 코드를 보면 string을 반환하는 함수와 아무것도 반환하지 않는 함수가 선언되어있는데, 후자의 함수에는 void
라는 선언이 붙은걸 확인할 수 있다.
// string 변수를 반환하는 변수
function func1(): string {
return "hello";
}
// 아무것도 반환하지 않는 함수
function func2(): void {
console.log("hello");
}
undefined, null VS void
아무것도 반환하지 않는 함수를 undefined이나 null 타입으로 정의한다면, return 문을 반드시 선언해야 한다.
그러니까, 함수의 끝에 return
부분을 꼭 적어야 한다는 것이다.
따라서 아무것도 반환하지 않고 return 문도 사용하고 싶지 않은 함수에 void를 사용하는 것이 좋다.
(2) never
never는 존재하지 않는, 존재 불가능한 타입을 말한다.
아래의 예시는 정상적인 종료가 불가능하여 해당 함수가 무언갈 반환하는 것이 애초에 불가능한 상황을 보여준다. 이런 함수에는 never 타입을 붙여줘야 한다.
function func3(): never {
while (true) {}
}
function func4(): never {
throw new Error();
}
만일 변수 타입으로 never를 정의하면 그 어떠한 값도 담을 수 없다. 아래의 코드는 전부 에러를 발생시킨다.
let a: never;
a = 1;
a = {};
a = "";
a = undefined;
a = null;
3. 타입 별칭과 인덱스 시그니처
타입 별칭(Type Alias)
type
키워드로 타입을 별도로 정의하는 방법이다. type 타입_이름 = 타입
형태로 타입을 정의한다.
일일이 기입해야 하는 타입의 길이를 줄여주기 때문에 중복 코드 제거가 가능하며 타입 프로퍼티의 추가 및 수정이 쉬워진다.
아래의 예시는 사용자가 type
으로 따로 정의한 User 타입과 이를 활용하여 생성한 user 객체를 보여준다.
user 객체변수에는 User 타입이 할당된 것을 확인할 수 있다.
type User = {
id: number;
name: string;
birth: string;
};
let user: User = {
id: 1,
name: "홍길동",
birth: "2000.00.00",
};
타입 별칭은 동일 스코프 내에 중복된 이름으로 선언할 수 없으며, 자바스크립트로 변환시 타입 별칭은 사라진다.
인덱스 시그니처(Index Signature)
인덱스 시그니처란 key와 value의 규칙으로 객체의 타입을 정의하는 것을 말한다.
만약 모든 key와 value가 string 타입이라면[key : string] : string
으로 편리하게 정의할 수 있다.
type CountryCodes = {
[key: string]: string;
};
let CountryCode: CountryCodes = {
Korea: "ko",
UnitedState: "us",
UnitedKingdom: "uk",
};
아래는 모든 key는 string 타입이고, 모든 value는 number 타입인 객체를 정의한 것이다.
type countryNumberCodes = {
[key: string]: number;
};
let countryNumberCodes: countryNumberCodes = {
korea: 410, // string: number
UnitedState: 840,
};
이때, 인덱스 시그니처는 규칙을 위반하지만 않으면 모든 객체를 혀용한다. 즉, 객체 변수에 빈 객체 {}를 할당해도 오류가 나지 않는다.
만약 객체 변수에 특정 값을 강제하고 싶다면 어떻게 할까? 이럴 때는 타입 정의시 해당 프로퍼티 추가하는 방법이 있다.
이때 중요한 것은, 추가된 프로퍼티의 value 타입이 인덱스 시그니처의 value 타입과 반드시 일치하거나 호환 가능해야 한다.
type countryNumberCodes2 = {
[key: string]: number;
Korea: number;
};
// let countryNumberCodes2: countryNumberCodes2 = {};// 오류
본 포스팅은 인프런 한 입 크기로 잘라먹는 타입스크립트 강의를 기반으로 작성되었습니다. 사용된 이미지들은 모두 위 강의에서 가져왔습니다. 문제시 알려주세요.
'웹개발 > TypeScript' 카테고리의 다른 글
타입스크립트 | 인터페이스 (0) | 2023.08.24 |
---|---|
타입스크립트 | 함수와 타입 (0) | 2023.08.24 |
타입스크립트 | 타입 이해하기 (0) | 2023.08.19 |
타입스크립트 | 컴파일러 옵션 설정하기 (0) | 2023.08.16 |
타입스크립트 | 기본 소개 (0) | 2023.08.16 |