한 입 크기로 잘라먹는 타입스크립트(TypeScript)
반 년 만에 재개하는 타입스크립트 포스팅...
타입스크립트가 자체적으로 제공하는 타입
위 그림은
타입스크립트가 제공하는 여러 개의 기본타입을 계층에 따라 분류한 타입 계층도
자바스크립트에서 사용하는 타입도,
생소한 타입도 있음
그리고 각각의 타입은 부모와 자식 관계를 이루며 계층을 형성
이 부모와 자식 관계를 어떤 기준으로 맺는지는 다음에!
number, string과 같은 원시 타입,
그리고 object, Array와 같은 비원시 타입
마지막으로 unknown, any, void, 와 같은 타입스크립트에서만 제공하는 타입도 살펴볼 것
npm init
새로운 패키지를 초기화하고
npm i @types/node
Node.js의 내장 기능들에 대한 타입 정보를 제공하는 패키지 설치
@types/node가 설치된 것 확인
이제 tsconfig 파일을 만듦
새 파일로 만들었음
- target: 변환되는 자바스크립트 코드가 사용할 자바스크립트 버전 명시
- module: 변환되는 자바스크립트 코드가 사용할 모듈 시스템 정리
- outDir: 컴파일 결과 생성되는 자바스크립트 파일이 위치할 경로 설정
- strict: 엄격한 타입 검사
- moduleDetection: 모든 타입스크립트 파일을 개별 모듈로 취급
- skipLibCheck: .d.ts 확장자를 가진 타입 선언 파일 전체(type declaration files) 에 대한 타입 검사를 하지 않도록 함
- include: 컴파일할 파일이 있는 경로
이제 타입스크립트 파일을 만들자!
src 폴더를 만들고
컴파일 하면,
dist 폴더가 생성되고
index.js 파일이 생성됨
이 파일에는 export 키워드가 있는데
moduleDetection 옵션을 force로 설정해뒀기 때문
➡️ 따라서 자동으로 컴파일러가 추가
이 컴파일된 자바스크립트 파일은 node로 실행
오류가 발생한다면...
Node가 export를 이해못하는 중
따라서 package.json에 타입을 추가한 후 재실행
오류 없이 실행됨
하나의 값만 저장하는 타입
배열이나 객체는 여러 개의 값을 저장하지만,
원시 타입은 숫자면 숫자, 문자면 문자, 딱 하나만 저장 가능
src에 새 파일을 만들자
(index.ts는 삭제)
숫자를 의미하는 모든 값 다 포함
숫자값 123 저장
위와 같이
변수 이름 뒤에 콜론 그 뒤에 타입을 정의하는 문법을
타입스크립트에서는 type 주석 혹은 type annotation이라고 함
이렇게 콜론과 함께 어떤 변수의 타입을 정의하는 방식은
타입스크립트에서 가장 기본적으로 변수의 타입을 정의하는 방식
음의 소수, 양의 소수는 물론이고
양의 무한대, 음의 무한대,
그리고 Not a Number라는 특수한 숫자도 포함됨
문자열을 넣으려고 하면 오류 발생
➡️ 에디터 상에서 프로그래머가 알 수 있게 명시됨
문자열 전용 메서드도 당연히 사용 불가
넘버 타입의 값에만 적용 가능한 메서드는 당연히 가능
: 뒤에 string이라고 명시
싱글 쿼터, 더블 쿼터, 백틱도 가능하고,
템플릿 리터럴 문자열도 가능
string 타입으로 정의한 변수에 number 타입의 값, 즉 숫자를 넣으려면 오류 발생
number 타입 전용 메서드도 불가능
문자열 전용 메서드는 가능
참과 거짓만 저장하는 타입
물론 당연히 이 변수에 숫자나 문자열을 저장하려면 오류
이 변수에는 null 값 외의 다른 값은 담을 수 없음
이와 같이 null과 undefined는 타입스크립트에서 별도의 타입으로 존재
자바스크립트에선 어떤 변수를 number 타입으로 만들어도 넣을 값이 없으면 잠시 null을 넣기도 하는데
타입스크립트는 이게 비허용!!
왜냐하면 null이란 값은 null 타입이 별도로 존재하고
number 타입 안에 포함되는 값이 아니기 때문에
그럼 진짜로 중간에 넣을 값이 없어서 잠시 null을 넣고 싶은 경우에는?
컴파일러 옵션을 조절해서
null 타입이 아닌 number 타입 같은 변수에도 임시로 null 값을 넣게 하기
분홍색으로 표시된 strictNullChecks 옵션 추가
이것 설정 시 TS 서버 재시작
이름부터가 엄격한 null 검사
➡️ 쉽게 말해서 null 타입이 아닌 변수에 null 값을 할당하는 걸 허용할지 말지에 대한 옵션
false 시 허용한다는 것
(null 타입이 아닌 변수에 null 값을 할당하는 걸 허용)
개발하는 상황에 따라
변수에 null 값을 임시로 넣어야 하는 상황이 많으면
이 옵션을 false로 설정하고 개발
무조건 안전한 코드만 쓰겠다고 하면
이게 기본적으로 true이니, 아예 명시하지 않거나
true를 명시하고 개발하면 됨
strictNullChecks 옵션은 strict 옵션의 하위 옵션
따라서 strict 옵션이 켜져 있으면 strictNullChecks 옵션도 켜지는 것
근데 지금처럼 하위 옵션 strictNullChecks을 따로 명시함으로써,
상위 옵션 strict이 true여도 false로 명시하고 사용 가능
강의에서는 안전하게 실습할 것이니
그냥 지우고 함
(그럼 다시 TS 서버 재시작)
number나 string 처럼
해당 타입에 해당하는 값이라면, 그 범위 내의 모든 값이 저장할 타입 뿐만 아니라
딱 하나의 값만 포함하는 리터럴 타입이라는 독특한 타입이 존재
그 자체가 타입이 되는 그런 타입
변수에 타입을 그 값 자체로 정의하면
이제 이 변수에는 이 값 외 다른 값을 넣을 수 없음
값으로 만든 타입 = 리터럴 타입
(왜냐하면 리터럴 = 값)
다른 값을 넣으면 오류가 남
string 도 마찬가지
boolean도 마찬가지
이처럼 타입스크립트는 타입 안에 포함되는 값 중에 하나를 마치 타입인 것처럼 정의해서 사용 가능
나중에 복합적인 타입을 만들 때 유용하게 사용
타입 정의 없이 숫자값을 담는 배열을 자바스크립트처럼 쓰면 위와 같음
이를 타입 어노테이션으로 타입 정의를 하려면,
콜론, 타입을 명시하고
이것이 배열임을 알리기 위해 대괄호 []를 명시함
문자열 배열도 마찬가지
string이란 타입을 적고
대괄호를 적어 배열 타입임을 알려줌
또한, 이렇게 배열 타입 정의도 가능
이렇게 꺽쇠를 열고 타입을 집어 넣는 문법을
제네릭 문법이라고 함
(강의에서는 앞으로 타입 어노테이션 방식으로 타입을 정의할 것)
지금까지는 배열에 들어가는 요소의 타입이 하나밖에 없었지만
(그러니까 숫자 값만 들어가는 배열 or 문자열 값만 들어가는 배열이었는데)
만약 배열에 들어가는 요소들의 타입이 다양하다면?
어떻게 타입을 정의해야 할까?
이때는 에디터에 마우스를 올려보자
타입스크립트가 어떻게 추론하는지 알 수 있음
소괄호 안에 요소의 타입이 써 있음
string | number
➡️ 배열의 요소가 string 타입이거나 number 타입일 수 있음
이를 유니온 타입이라고 함
이를 활용해 타입 주석을 달아보자
배열에 들어가는 요소들의 타입이 다양할 경우
위와 같이 정의할 수 있음
배열 안에 배열, 그러니까 2차원 배열이나 3차원 배열
다차원 배열의 타입을 정의하자
이렇게 배열이 있고 그 안에 또 배열이 들어갈 수 있음
이렇게 쓸 수 있다는 건 알겠음
그래서 이 배열은 어떻게 정의?
지금은 숫자 타입의 배열만 저장하고 있으니까,
숫자 타입의 배열을 배열로 저장한다는 뜻으로 보자
튜플이란,
길이와 타입이 고정된 배열
자바스크립트의 배열은 길이와 타입이 고정되어 있지 않음
개수를 마음대로 늘릴 수도 있고,
배열에 들어가는 요소의 타입도 자유로움
그리고,
타입스크립트의 배열은 배열에 들어가는 요소의 타입을 고정시킬 수는 있지만,
길이까지 고정시킬 수는 없음
그러나,
튜플은 타입과 길이를 모두 고정 가능
이렇게 각 요소의 타입을 지정해주면
지정한 타입이 해당 자리의 요소의 타입이고,
지정한 만큼 길이가 지정됨
길이나 타입을 만족하지 않으면 요소를 담을 수 없음
당연히 순서가 바뀌어도 안 됨
튜플은 별도로 존재하는 자료형이 아니고 그냥 배열임
그래서 tsc를 사용하여 컴파일하고,
자바스크립트 코드를 보면
그냥 배열임
그래서 push나 pop 같은 배열 메서드를 사용하여
값을 넣거나 제거하는 것이 가능
근데 길이를 2개로 고정해뒀는데,
push로 한 개 더 넣어도 오류가 발생하지 않음
배열 메서드를 사용할 때는 튜플의 길이 제한이 발동하지 않음
이걸 자바스크립트의 배열이라고 생각하기 때문에 알아보지 못함
pop 메서드를 여러 번 사용해도 어떤 오류도 발생하지 않음
(1번 push 했으니 3번 pop 해도 되지 않나? 싶어서 4번 pop해봤지만, 역시 오류가 나지 않음)
➡️ 따라서 튜플 타입을 사용할 땐,
배열 메서드를 사용하여 push나 pop 같은 방식으로
요소를 추가하거나 제거하는 기능을 사용할 때 각별히 주의하는 것이 좋음
예를 들어 유저 정보를 2차원 배열로 저장하는 배열을 생각해보자
이렇게 배열의 규칙을 정리해서 만들었는데,
동료가 눈치 없이 이상하게 유저를 추가함
보기에는 그럴 수도 있다 싶지만(아니, 그럴 수 없어)
나는 0번 인덱스를 이름으로 정리해두고
toUpperCase 같은 메서드도 사용함
그런데 이때 0번 인덱스에 숫자 타입의 값을 적어두는 바람에 오류가 발생할 수도 있음
그래서 이때도 타입을 정의해주면 됨
[string, number] 튜플을 []를 사용하여 배열로 정의했기 때문에
[4, "한입넥스트"]라는 데이터는 타입이 맞지 않으므로 오류라고 감지
이럴 때 활용할 수 있다!😇
간단한 객체를 하나 만들어보자
유저의 정보를 저장하는 객체를 만들었음
이때 이 객체를 담고 있는 이 변수 유저의 타입은 뭐가 되어야 할까?
타입스크립트에서는 object라는,
객체를 의미하는 타입이 있음
위 user도 객체니까,
object타입으로 정의해보자
이렇게 정의하면 문제가 생김
점 표기법으로 객체의 프로퍼티에 접근하려면 오류가 발생
object 타입에 id 프로퍼티가 없다고 함
왜? id는 정의되어 있는데?
왜냐하면 타입스크립트에 object라는 타입은
이 값이 객체다! 라는 정보 외에는 없는 타입이기 때문에
object로 정의하면 객체의 프로퍼티나 메서드에 뭐가 있는지
이 타입은 알 수가 없음
즉, 변수를 object로 정의하면
이 변수는 객체이긴 한데, 그 이상은 몰라
라고 하는 것과 동일한 것임
근데 우리는 어쨌든 객체를 정확히 타입으로 만들고 싶단 말임!
➡️ 객체 리터럴 타입 활용
이렇게 프로퍼티의 타입까지 모두 정의!
객체 리터럴 문법과 비슷하기 때문에
중괄호를 이용해 객체의 타입을 정의하는 방식을
객체 리터럴 타입이라고 함
이렇게 객체 리터럴 타입으로 변수 유저의 타입을 정의하면,
점 표기법으로 id 프로퍼티에 접근하는 코드도 오류없이 수행됨
id 프로퍼티 위에 마우스를 올려보면,
우리가 객체 리터럴 타입으로 정의한 대로
id 프로퍼티 타입이 number로 나타내는 것 확인 가능
결론적으로 객체의 타입을 정의할 때 object를 사용하면,
객체인 건 알지만
프로퍼티나 메서드에 접근하면 오류가 나기 때문에 잘 쓰지 않고,
이렇게 객체의 모든 프로퍼티들의 타입까지 구조적으로 다 정의할 수 있는 방식인
객체의 리터럴 타입을 사용한다고 알아두면 됨
복습 겸 강아지 객체를 만들어 보자
이렇게 객체의 타입을 프로퍼티 기반으로 정의
C나 자바 같은 정적인 타입 시스템 언어를 사용해본 사람이라면(나?)
이렇게 객체 타입을 정의할 때 프로퍼티를 일일이 나열하면서,
프로퍼티를 기반으로 객체 타입을 정의하는 문법이 당황스러울 수 있음
위 말만 들으면 사실, C나 자바도 타입을 정의하는 방식인데 뭐가 다르지? 싶었음
Java의 객체 정의 방식
class Person { String name; int name; }Person이라는 이름이 있는 타입을 만들고 그 안에 필드 선언
타입스크립트에서의 객체 타입 정의 방식
type Person = { name: string; age: number; }비슷해 보인단 말임🥹
하지만, 타입스크립트는 이 객체는 이 프로퍼티를 가져야 한다고 형태를 나열하는 것
그러니까, 다시 말해 모양이 같으면 다른 타입으로 취급된다고 함예를 들면,
type A = { name: string }; type B = { name: string }; let a: A = { name: "홍길동" }; let b: B = a; // 가능Java 관점에서 A와 B는 다른 타입이지만,
타입스크립트에서는 구조가 같기 때문에 동일하게 취급된다고 함그래서 직접 또 돌려봄
![]()
![]()
다시 말해 타입스크립트는 name만 있으면 A타입이라고 하자~가 되는 언어임
다시 돌아가서,
사실 대부분의 언어에서는
타입을 정의할 때 객체면 전부 Object고,
문자열이면 전부 String인 식인데,
타입스크립트는
User 객체만의 타입을 id, name 프로퍼티 기반으로 정의하고
Dog 객체만의 타입을 name, color 프로퍼티 기반으로 정의
마치 id와 name이 있어야 User 객체고,
name과 color가 있어야 Dog 객체인 것
정리하자면,
object 같은 단순한 이름으로 타입을 정의하는 게 아니라
이 객체를 이루는 프로퍼티나 메서드가 어떻게 생겼는지
객체의 구조를 기준으로 타입을 정의
➡️ 구조적 타입 시스템라고 함
혹은 프로퍼티를 기준으로 타입을 결정하는 시스템이니까
➡️ 프로퍼티 기반 타입 시스템이라고도 함
(이건 공식적인 명칭은 아닌 듯)
자바의 경우에는 이름을 기준으로 정의하기 때문에
명목적 타입 시스템이라고 함
(챗지피티 땡큐)
가끔 어떤 프로퍼티는 없어도 되는 경우가 있음
user의 경우,
이름은 아는데 아이디는 모를 수가 있음
그런데 이미 user라는 변수의 타입을
id와 name이라는 두 개의 프로퍼티를 갖는 객체로 정의해놨기 때문에
id를 모른다고 작성하지 않으면 오류 발생
➡️ 선택적 프로퍼티라고 명시해야 함
프로퍼티 뒤에 물음표 추가
물음표가 붙으면, 해당 프로퍼티가 있어도 되고 없어도 됨
근데 만약 있으면 number 타입이어야 함!
➡️ 선택적 프로퍼티 혹은 옵셔널 프로퍼티라고 함
타입까지 야무지게 지정한 객체
그런데 자바스크립트에서는 객체의 프로퍼티에 접근해서 프로퍼티의 밸류를 바꿀 수 있음!
프로퍼티가, 딱 봐도 바꾸면 안 될 것 같이 생김
따라서 readonly라는 키워드를 사용해서 읽기 전용 프로퍼티로 만들어줌
그럼 해당 프로퍼티를 변경할 수 없음
위와 같은 변수가 있다고 하자
위와 같이 유저의 정보를 저장하는 변수를 하나 더 선언해보자
(유저가 하나이면,... 슬프니까. 여럿이어야 하니까)
정의하는 것만 중복 코드이고,
길이도 길게 차지함
타입을 마치 변수처럼 정의해서 사용하는
타입 별칭을 만들어 코드의 중복을 제거하자
유저를 저장할 객체의 타입을 작성할 것이기 때문에
User라는 타입을 선언하고,
변수에 값을 초기화
그리고 안의 프로퍼티, 객체를 채워줌
➡️ 타입 별칭으로 만든 유저라는 타입이 생성됨
그러면 위처럼 변수User의 타입 어노테이션으로 객체 타입 리터럴을 일일이 작성할 필요가 없고,
대신 이 타입 별칭을 가져다가 씀
위와 같이
매번 프로퍼티의 타입을 쓸 필요가 없고, 중복 코드가 제거됨
만약 User 객체 타입에 새로운 프로퍼티가 필요하다면,
타입 별칭에 새로 추가하면 됨
그럼 User라는 타입으로 정의되어 있는 모든 변수에 공통적으로 반영됨
따라서 앞으로 공통적으로 적용되어야 하는 User 같은 타입의 경우에는,
대부분 타입 별칭을 이용할 것
그리고 이 타입 별칭을 사용할 때 조심해야 할 것!
let 키워드로 선언하는 변수처럼,
동일한 스코프에 중복된 이름으로 타입 별칭을 선언하면 오류 발생
마치 변수의 이름같음
그렇기 때문에 타입 별칭을 선언할 때는 같은 스코프 내에서 중복되지 않도록 해야 함
만약 함수 내에 User를 정의하면,
이는 함수 안팎에서 각각의 스코프를 따라감
그러니까 함수 밖의 User는 함수 밖의 타입이고,
함수 안의 User는 함수 안의 타입이라서,
함수 내에서 User 타입을 사용하면 함수 안의 User타입을 따라감
(이렇게 말하면 어렵지만, 자바스크립트의 스코프를 공부했거나, 다른 프로그래밍 언어를 공부했다면 무슨 뜻인지 대충 알 것이다.)
아무튼,
타입스크립트의 타입 관련 코드는 컴파일 결과 자바스크립트 코드에선 다 제거됨
그렇기 때문에 타입 별칭으로 만든 타입도 제거됨
이렇게 타입스크립트에서
타입을 마치 변수처럼 정의하도록 도와주는 문법이
타입 별칭(타입 Alias)임
이렇게 객체를 만들고
국가의 이름과, 영문 코드인 객체를 만듦
타입 별칭으로 정의하면,
위와 같이 정의하게 됨
그런데 지금이야 3개의 프로퍼티밖에 없지만,
만약에 초거대 글로벌 서비스가 되어 약 200개의 가까운 모든 국가의 코드를 넣어야 한다면?
➡️ 타입 별칭도 모든 프로퍼티를 다 넣어줘야 함...
세상에...😱
그런데 가만 살펴보면
프로퍼티가 다 string 타입임
국가 코드인 value도 string 타입
➡️ 키가 string 타입이고, value가 string 타입인 프로퍼티는 모두 허용하도록 타입을 만들면
어떤 국가를 추가하든 문제가 되지 않음
key와 value의 규칙을 기준으로 객체의 타입을 정의할 수 있는 문법
➡️ 인덱스 시그니처

)
대괄호 안에 key의 타입을 쓰고
콜론,
그리고 value의 타입 명시
그러면 객체 contryCodes의 타입을,
우리가 만든 타입 별칭으로 지정 가능
이제 오류 없이
정상적으로 타입을 잘 정의함
이와 같이
key와 value의 타입을 기준으로 규칙을 이용해서
유연하게 객체의 타입을 정의하는 문법을 인덱스 시그니처라고 함
key와 value의 타입이 어떤 규칙을 가지고 움직이는 객체의 타입을 정의할 때 굉장히 유용하게 사용 가능
연습 삼아 객체 하나 더
countryNumberCode 라는 객체를 만들어보자
이렇게 key는 string이지만, value는 number 타입인 객체를 선언하려면?
위와 같이 인덱스 시그니처를 이용해 간결하게 타입 정의 가능
활용 가능
또 다른 특징 한 가지는,
객체의 프로퍼티를 지워도 상관 없음
왜냐하면! 인덱스 시그니처 타입은 규칙을 위반하지만 않으면 모든 객체 허용
지금 이 객체는 아무 프로퍼티가 없음
➡️ 위반할 프로퍼티가 없음
아무런 프로퍼티가 없으니까 규칙을 위반할 것도 없는데,
이런 건 때로 주의해야 함
따라서 꼭 있어야 할 프로퍼티가 있다면,
필수 프로퍼티를 적어주면,
해당 프로퍼티를 꼭 적어야 한다고 에디터가 알려줌
마음이 바뀌어서
나라 숫자 코드뿐 아니라 영어 코드도 저장하고 싶을 때,
(당연히 오류남)
그럼, Korea는 허락해보자
(응, 돌아가)
우리가 인덱스 시그니처를 사용하는 어떤 객체 타입에서
추가적인 프로퍼티를 정의하려면
추가적인 프로퍼티의 value의 타입은
인덱스 시그니처의 value의 타입과 일치하거나 호환해야 함
그런데, Korea라는 프로퍼티의 value 타입이 string이고,
인덱스 시그니처의 value의 타입은 number이기 때문에 문제가 생김
따라서 이는 불가함~
여러 가지 값에 이름을 부여해 열거해두고 사용하는 타입
자바스크립트에는 없고
타입스크립트에만 제공되는 타입
세 명의 유저가 있다고 가정
각각의 유저에 롤을 부여
유저의 권한은 이렇게 숫자로 배정하는 방법을 많이 사용
이렇게 숫자로 각각의 권한을 설정한 다음 계속 개발하다 보면
언젠가 한 번은 까먹을 수도 있음
숫자만 보고 기억하기 어렵기 때문
➡️ 타입스크립트의 Enum을 활용
enum이란 키워드를 적고 이름을 적고(Role),
중괄호를 열고 각 권한을 써줌
각각의 멤버에 원하는 대로 값을 지정
그리고 각 변수의 role을 enum을 활용하여 지정
➡️ 각각의 role이란 프로퍼티에 0, 1, 2가 저장됨
콘솔로 출력해보면 할당된 값 확인
만약 숫자를 0이 아닌 10부터 할당하고 싶으면
맨 위에 숫자 10 명시
중간부터 다른 숫자 할당도 가능
그럼 0, 10, 11 순으로 할당됨
enum을 사용할 땐 숫자를 자동으로 할당할 수도 있고,
직접 시작하는 숫자를 지정할 수도 있음
이렇게 긱각의 멤버의 값이 숫자로 할당되는 enum을 숫자형 enum이라고 함
문자열 값도 할당할 수 있음
프로퍼티에 할당해 보면,
콘솔로 출력해보면 할당된 값 확인
language enum을 사용하지 않으면
language 프로퍼티에 값을 할당하다가,
korea인지 ko인지 Ko-KR인지 헷갈리는데
enum을 활용하면 헷갈리지 않고 바로바로 확인 가능
타입스크립트의 타입 관련된 코드는
(role이나 language 같은 enum은) 다 사라진다는데
프로퍼티에 enum을 점 표기법으로 가져와서 할당해도 됨?
결론부터 말하자면,
enum은 컴파일 결과 사라지지 않음
복잡하지만,
enum이 자바스크립트의 객체로 변환되는 중
결론적으로 타입스키립트의 enum은 컴파일 결과 사라지지 않고,
자바스크립트의 객체로 변환되므로
코드 상에서 점 표기법이나 값을 사용하듯 사용할 수 있음
자바스크립트에는 없고, 타입스크립트에만 있는 타입
특정 변수의 타입을 우리가 확실히 모를 때 사용할 수 있는 타입
예를 들면,
let anyVar = 10;
anyVar는 매우 범용적으로 사용해야 한다고 가정
지금은 숫자 10이지만 나중에는 문자열이 되어야 한다고 하자
오류가 발생함
왜냐하면,
타입스크립트는 우리가 변수의 타입을 지정하지 않아도
초기화하는 값을 기준으로 변수의 타입을 자동으로 추론하기 때문에
anyVar는 숫자값 10으로 초기화
➡️ 자동으로 number 타입으로 추론
그러니까 이후 문자열 값을 넣으려면 오류 발생
만약 자바스크립트 변수 쓰듯이 타입 검사 없이,
즉 타입 상관없이 아무 값이나 담고 싶다면?
any 타입을 이 변수에 지정
any는 우리 말로 모든 또는 누구나, 라는 뜻으로 볼 수 있음
➡️ any 타입 = 어떤 타입(아무 타입도 상관 ❌)
즉, 변수의 타입을 any로 지정하면 어떤 타입이든 이 변수에 넣을 수 있음
따라서 불리언, 객체, 함수도 넣을 수 있음
문자열 메서드나 숫자 메서드도 제약 없이 사용 가능
let num: number = 10;
num = anyVar;
number 타입의 변수를 만들고,
그 number 타입의 변수에 any 타입의 변수를 넣어도
타입 오류가 발생하지 않음
any타입은 변수에 지정할 경우,
모든 타입의 값을 다 할당 받을 수 있고
모든 타입의 변수에 다 any타입의 값을 집어넣을 수 있음
따라서 타입스크립트의 타입 검사를 다 통과하는 치트키 같은 타입
이제 이걸 실행 시켜 보자
오류가 발생!
왜냐면, 지금 마지막으로 들어간 값이 함수인데,
문자열 메서드인 toUpperCase 메서드를 호출하려고 하니 당연히 안 됨
➡️ 타입 에러가 런타임 도중 발생
이게 문제!!!
any 타입은 타입 검사를 어찌되든 다 통과하는 치트키 같은 타입
= 타입 검사를 안 함
변수에 any 타입을 지정한다는 건,
타입스크립트의 이점을 포기한다는 것
즉, 오류가 있는 코드도 다 검사를 통과하고
런타임 도중 에러가 발생하는 최악의 상황을 유발
그렇기 때문에 any타입은 가능한 한 최대한 사용하지 않는 것이 좋음
any와 비슷하지만 조금 다름
타입은 unknown이라고 지정
여기에 문자열이든 숫자든 함수든 객체든,
any 타입의 변수를 선언한 것처럼
아무 타입의 값이나 집어넣을 수 있음
지금까지느 any와 똑같음
➡️ 우리가 변수에 어떤 타입이 들어올지 모르겠는 경우
any나 unknown 둘중 하나를 쓸 수 있음
차이점이 있다면,
unknown 타입은 any 타입과 다르게
모든 값을 저장할 순 있지만, 그 반대는 안 됨
any 타입은 number 타입에도 값을 저장할 수 있었지만,
unknown은 불가
당연히 number가 아닌 다른, 모든 타입의 변수에 unknown 타입의 값을 넣을 수 없음
또 any와 다르게 toUpperCase 같은 특정 타입의 메서드를 사용할 수 없음
덧셈, 뺄셈, 곱셈, 나눗셈 같은 연산도 불가함
단,
만약에 unknown 타입의 값을 활용하고 싶다면
조건문으로 typeof 연산자를 통해
이 unknown 변수가 number 타입임을 확실히 밝혀주었을 때만
unknown 타입의 변수를 number 타입으로 정제해서 사용 가능
➡️ 이러한 과정을 타입 정제 혹은 타입 좁히기라고 함
중요한 건 any 타입과 unknown 타입은 변수의 타입으로 지정하면,
이 변수는 모든 타입의 값을 다 할당받을 수 있지만,
any 타입은 반대로도 가능
unknown 타입은 반대로는 불가
그렇기 때문에 변수에 저장할 값의 타입이 확실하지 않을 때는
any 타입보다 unknown 타입이 나음
적어도 어떤 연산이나 어떤 메서드나 어떤 변수에나 값을 넣을 수는 없기 때문에
런타임 에러를 일으키는 any 타입보다는 unknown이 나음
공허라는 뜻
아무것도 없다.
즉, void 타입은 아무것도 없음을 의미하는 타입
function func1() {
return "hello";
}
함수가 하나 있음
그냥 문자열을 반환
참고로 타입스크립트에서는 함수의 반환 값에도 타입 정의 가능
매개변수를 작성하는 소괄호 뒤에 타입 주석을 쓰면 됨function func1(): string { return "hello"; }이 함수의 반환값은 string 타입이다라고 명시하는 것임
function func2(): void {
console.log("hello");
}
이렇게 함수가 아무것도 반환하지 않을 때의
반환값 타입은? ➡️ void 타입
변수의 타입에도 void 정의 가능
➡️ 어떤 값도 저장 못하고 오직 undefined만 담을 수 있음
예외적으로 strictNullChecks 검사를 끄면
void에 null을 저장할 수 있음
➡️ 왜냐하면 이 옵션이 꺼지면, null이 어느 타입의 변수에도 들어갈 수 있으니까
별거 아니지만,
굳이 void의 필요성은?
우리는 이미 자바스크립트를 배울 때 아무것도 없을 때 나타내는 값이 undefined라고 배움
null도 있고
굳이 반환값이 없는 함수의 반환값 타입을 정의할 때
undefined나 null이 아닌
void를 쓰는 이유는?
이렇게 함수의 반환값을 undefined로 정의하면
이 함수는 undefined 값을 반환해야 함
혹은 이런 식으로
(근데, 타입스크립트 버전이 올라가면서 지금은 undefined로 타입값을 정의하고,
아무것도 반환하지 않아도 문제 없음)
그런데 null은 반환값 타입으로 정의하면
return null이 필수
따라서 return문을 사용하고 싶지 않은 경우
함수의 반환값 타입으로 void 사용
존재하지 않는,
불가능한 타입
새로운 함수를 만들어보자
function func3() {
while (true) {}
}
무한루프를 도는 함수
아무것도 반환하지 않으니까 반환값은 void?
void는 함수가 정상적으로 종료되지만,
반환값이 없어서 void 타입인 것임
이 함수는 반환할 수가 없어서 애초에 정상적인 종료가 되지 않기 때문에
이 함수가 뭔가를 반환하는 것 자체가 모순
function func3(): never {
while (true) {}
}
따라서 정상적으로 종료 자체가 되지 않기 때문에
함수에 반환값이 있는 것 자체가 모순일 경우
반환값을 never로 지정
자바스크립트는 실행 도중 에러를 던져줄 수 있었음
이때는 실행되면 바로 프로그램이 중지되기 때문에
반환값으로 never가 제일 적합
즉, never는 불가능이고 모순을 의미함
never도 변수에 정의할 수 있지만
void와 마찬가지로 아무 값도 담을 수 없음
심지어 undefined를 담을 수 있던 void와는 달리
never는 undefined도 담을 수 없음
null도 담을 수 없음
tsconfig.json에서 strictNullChecks 옵션을 꺼도 불가
any 타입의 값도 never 타입의 변수에는 담을 수 없음
이렇게 never 타입은 변수의 타입으로 활용하면
그 어떤 값도 저장할 수 없는,
그 어떤 값도 저장하는 게 말이 안 되는
변수의 타입을 정의할 때도 활용 가능