값과 이 값으로 할 수 있는 일의 집합
예를 들어, 어떤 값이 True라면 이 값을 가지고 어떤 일을 할 수 있고 어떤 일을 할 수 없는지도 알 수 있다.
이제 본격적으로 타입스크립트에서 이용할 수 있는 타입을 살펴보고, 각 타입의 역할을 살펴볼 것
기존에 존재하지 않던 n: number를 변수명 옆에 넣음으로서 에러를 발생시켜줌
타입 어노테이션이 없으면 squareOf 매개변수에 제한이 없으므로 아무 타입이나 전달 가능, 어노테이션이 존재하고 이를 경계 개념으로 해석한다면 n의 상위 한정값이 number임을 전달하여 number이상의 것이라면 n에 할당할 수 없게 된다.
타입들의 대부, any로 뭐든지 할 수 있지만 꼭 필요한 상황이 아니라면 사용하지 않는 것이 좋음
타입스크립트에서는 런타임이 아닌 컴파일 타임에 모두가 타입이 있어야 하므로 프로그래머와 타입스크립트 둘 다 타입을 알 수 없는 상황에서는 기본 타입인 any라고 가정
any는 최후의 보루로서 가급적 사용 하지 않아야함
any를 사용하면 값이 자바스크립트처럼 동작하기 시작하면서 타입 검사기라는 마법이 더 이상 작동하지 않게 됨 (눈을 감고 비행하는 것과 마찬가지)
두 개의 any를 더하라 지시 했으므로 이럴 경우 에러가 나오지 않음
TSC 플래그 : noImplicitAny
암묵적인 any가 나타났을 때 예외를 일으키고 싶다면 tsconfig.json 파일에서 noImplicitAny를 활성화 (strict가 활성화라면 따로 안 해도 됨)
타입을 미리 알 수 없는 어떤 값이 있을 때 any 대신 unknown을 사용
any처럼 unknown도 모든 값을 대표하지만, unknown의 타입을 검사해 정제 (refine)하기 전까지는 타입스크립트가 unknown 타입의 값을 사용할 수 없게 강제
unknown이 지원하는 연산 (비교 연산 ==, ===, ||, &&, ?)과 반전 (!)을 지원하고 자바스크립트의 typeof, instanceof 연산자로 정제할 수 있음
- 타입스크립트가 무언가의 타입을 unknown이라고 추론하는 상황은 없고 unknown 타입을 사용하고자 한다면 개발자가 명시적으로 설정 (a)
- unknown 타입과 아닌 값 비교 가능 (b)
- unknown 값이 특정 타입이라고 가정하고 해당 타입에서 지원하는 동작을 수행할 수는 없고 (c) 먼저 타입스크립트에게 해당 값이 특정 타입임을 증명해야 함 (d)
불린형으론 알다시피 비교연산과 반전연산만 할 수 있을 뿐 많은 연산을 지원하진 않는다
- 어떤 값이 boolean인지 타입스크립트가 추론하게 함 (a, b)
- 어떤 값이 특정 boolean인지 타입스크립트가 추론하게 함 (c)
- 값이 boolean임을 명시적으로 타입스크립트에 알림 (d)
- 값이 특정 boolean임을 명시적으로 타입스크립트에 알린다 (e, f)
보통 실제로는 1. 과 2. 방식을 쓰고 추가적인 타입 안전성을 얻을 목적으로는 가끔 4. 를 이용하기도 함
2.와 4. 같은 경우는 새로운 내용
변수 e는 평범한 불린이 아니라 e는 boolean true라는 특정 값을 갖고 있어 라고 말함
-> 즉, 값을 타입으로 활용하므로 e와 f에 사용할 수 있는 값은 boolean 타입이 가질 수 있는 값 중 특정한 하나의 값으로 한정 이러한 기능을 타입 리터럴이라고 부름
타입 리터럴 (type literal)
오직 하나의 값을 나타내는 타입
모든 곳에서 일어날 수 있는 실수를 방지해 안전성을 추가로 확보해주는 강력한 언어 기능
명시적으로 타입 리터럴 설정
추론
const를 활용했으므로 타입스크립트는 그 변수의 값이 절대 변하지 않으리라는 사실을 알게 되어 해당 변수가 가질 수 있는 가장 좁은 타입으로 추론
let a = 1234 // number
var b = Infinity * 0.10 // number
boolean 예제처럼 4가지 방법으로 number 타입 지정 가능
- 타입스크립트가 값이 number임을 추론하게 함 (a, b)
- const를 이용해 타입스크립트가 값이 특정 number임을 추론하게 함 (c)
- 값이 number임을 명시적으로 타입스크립트에 알림 (e)
- 타입스크립트에 값이 특정 number임을 명시적으로 알림 (f, g)
boolean처럼 개발자들은 대개 타입스크립트가 number 타입을 추론하도록 만듦 (첫 번째)
상황에 따라서는 number 타입이 특정 값으로 제한되도록 처리해야할 수도 있음 (두 번째 또는 네 번째) number 타입임을 명시해야하는 상황은 거의 없음 (세 번째)
긴 숫자를 처리해야할 땐 숫자 분리자를 활용 가능 1_000_000 // 1000000과 같음
자바스크립트와 타입스크립트에 새로 추가된 타입으로, 이를 이용하면 라운딩 관련 에러 걱정없이 큰 정수를 처리할 수 있다 number는 2^53까지의 정수이고 이는 더 큰 수를 표현이 가능함
얘도 마찬가지로 선언하는 방법이 4가지이다. 가능하면 타입스크립트가 bigint의 타입을 추론하게 만드는 게 좋음
당연하게도 모든 문자열의 집합으로 연결(+)과 슬라이드 (.slice) 등의 연산을 수행할 수 있음
선언 4가지 방법이고 string 타입 추론 하게 두는 것이 좋음
ES2015에 새로 추가된 기능, 실무에서는 심벌을 자주 쓰지는 않고
객체와 맵에서 문자열 키를 대신하는 용도로 사용
이를 사용하면 잘 알려진 키만 사용하도록 강제할 수 있으므로 키를 잘못 설정하는 실수를 방지
객체의 기본 반복자 (Symbol.iterator)를 설정하거나 객체가 어떤 인스턴스인지 (Symbol.hasInstance)를 런타임에 오버라이딩 하는 것과 비슷한 기능을 제공
symbol 타입으로는 할 수 있는 동작이 별로 없음
자바스크립트에서 Symbol('a')는 우리가 준 이름으로 새로운 symbol을 만든다는 의미
symbol은 고유하여 다른 심볼과 == 또는 ===로 비교했을 때 같지 않다고 판단 (당연히 같은 이름을 주어도)
let으로 선언하면 number로 추론되고 const를 붙이면 특정 숫자 27로 추론 되듯이 symbol도 symbol 타입으로 추론되거나 아니면 명시적으로 unique symbol을 정의할 수 있음
즉, unique symbole도 결국 1, true, "literal" 등 다른 리터럴 타입과 마찬가지로 특정 symbol을 나타내는 타입
타입스크립트의 객체 타입은 객체의 형태를 정의
{}로 만든 객체와 new를 사용해 만든 객체는 구분할 수 없음
이는 자바스크립트가 구조 기반 타입 (Structural type)을 갖도록 설계 되었기 떄문
따라서 타입스크립트도 이름 기반 타입이 아니라 자바스크립트 스타일을 선호함
구조 기반 타입화
구조 기반 타입화에서는 객체의 이름에 상관없이 객체가 어떤 프로퍼티를 갖고 있는지는 따짐, 일부 언어에서는 덕 타이핑 이름이라고 함
let a : object = {
b : 'x'
}
b에 접근하면 어떻게 될까?
사실 object는 any보다 조금 더 좁은 타임, object는 서술하는 값에 관한 정보를 거의 아렬주지 않고 값 자체가 그저 자바스크립트 객체라고 (null도 아니라고) 말해줄 뿐이다
그렇다면 명시적으로 정의하지 않고 타입스크립트가 추론할 땐?
객체 리터럴 문법 즉, 객체 타입을 만드는 두 번째 방법을 발견했다 (타입 리터럴과 혼동 X)
타입스크립트가 c의 형태를 추론하게 하거나 중괄호 ({}) 안에서 명시적으로 타입을 묘사할 수 있음
이렇게 되더라도 b는 여전히 number이다 const를 사용하느냐 let을 사용하느냐에 따라 타입스크립트가 number나 string 타입을 어떻게 추론하는지 알 수 있음
자바스크립트의 객체값을 바꿀 수 있듯이 타입스크립트도 여러분이 객체를 만든 후 필드를 나중에 바꾸려한다는 걸 알기 때문
객체 리터럴 문법은 "이런 형태의 물건이 있어"라고 말한다. 이 물건은 객체 리터럴 또는 클래스일 수 있음
{firstName : string, lastName string}은 객체의 형태를 묘사하며 객체 리터럴과 클래스 인스턴스 모두 이 형태를 만족하므로 타입스크립트는 Person을 c로 할당하는 동작을 허용
프로퍼티를 추가하거나 필요한 프로퍼티를 제공하지 않으면 벌어나는 일
'c'는 알려지지 않았으므로 프로퍼티 추가가 되지 않았음
확실한 할당
타입스크립트는 변수를 사용하기 전에 값을 할당하도록 강제함
타입스크립트는 객체 프로퍼티에 엄격한 편이라 객체에 number 타입의 b라는 프로퍼티가 있어야 한다고 하면 타입스크립트는 오직 b만을 기대
b가 없거나 다른 추가 프로퍼티가 있으면 에러를 발생시킴
그렇다면 어떤 프로퍼티는 선택형이고 예정에 없던 프로퍼티가 추가될 수 있다고 타입스크립트에 알리는 방법?
a에 할당할 수 있는 객체타입
a = { b : 1 }
a = { b : 1, c : undefined }
a = { b : 1, c : 'd' }
a = { b : 1, 10: true}
a = { b : 1, 10: true, 20: false}
a = {10: true } // 에러 'b' 프로퍼티가 없음
a = {b: 1, 33: 'red'} // 에러 string형은 boolean에 할당될 수 없음
인덱스 시그니처 (index signature)
[ key : T ] : U 같은 문법을 인덱스 시그니처라고 부르며 타입스크립트에 어떤 객체가 여러 키를 가질 수 있음을 알려준다."이 객체에서 모든 T타입의 키는 U 타입의 값을 갖는다"라고 해석할 수 있음
키값의 이름은 number고 값은 boolean
인덱스 시그니처를 이용하면 명시적으로 정의한 키 외에 다양한 키를 객체에 안전하게 추가할 수 있음
단, 한 가지의 규칙으로는 인덱스시그니처의 키는 반드시 number나 string 타입에 할당할 수 있는 타입이어야 함
키의 이름은 원하는 이름을 가져다 바꾸어도 됨 즉, key가 아니어도 가능
readonly 한정자를 이용해 특정 필드를 읽기 전용으로 정의할 수 있음 (정의한 필드에 초기값을 할당한 다음에는 그 값을 바꿀 수 없다. 객체 프로퍼티에 const를 적용한 듯한 효과를 냄)
let user : {
readOnly firstName : string
} = {
firstName : 'abby'
}
user.firstName // string
user.firstName = 'abbey with an e' // 에러, firstName은 읽기 전용프로퍼티 이므로 할당 X
대부분 첫 번째난 세 번쨰 방법을 이용, 두 번째와 네 번째 방법은 피해야 함
값의 타입이 무엇인지에 따라 수행할 수 있는 연산이 달라진다 +로 두 숫자를 더하거나, .toUpperCase로 문자열을 대문자로 만들 수 있다
값 뿐만이 아니라 타입에도 어떤 동작을 수행할 수 있다
타입 별칭으로 타입을 가리키는 방법
Age는 number인데 타입 별칭을 이용하여 Person의 형태를 조금 더 이해하기 쉽게 정의할 수 있다. 타입스크립트는 별칭을 추론하지는 않으므로 반드시 별칭의 타입을 명시적으로 정의해야함
Age는 type Age = number를 통해 별칭이 되었으므로 명시적으로 정의를 해줌
따라서 위 코드를 아래로 바꿀 수 있음
타입 별칭은 프로그램의 논리에 영향을 미치지 않고 별칭이 가리키는 타입으로 대치할 수 있음 하지만 변수처럼 하나의 타입을 두 번 정의할 순 없음
let과 const처럼 타입 별칭도 블록 영역에 적용됨
모든 블록과 함수는 자신만의 영역을 가지므로 내부에 정의한 타입 별칭이 외부의 정의를 덮어씀
타입 별칭은 복잡한 타입을 DRY(Don't Repeat Yourself) 하지 않도록 변수가 어떤 목적으로 사용되었는지 쉽게 이해할 수 있게 도와줌 (어떤 사람들은 변수명보다 타입명으로 설명하는 것을 선호함)
값을 변수로 할당할지를 결정하는 것처럼 타입 별칭을 사용할지 여부를 결정
타입스크립트는 타입에 적용할 수 있는 특별한 연산자닌 유니온 (|)과 인터섹션 (&)을 제공함 타입은 집합과 비슷하므로 집합처럼 연산을 수행할 수 있음
CatOrDogOrBoth 를 통해 우리는 문자열 타입의 name 프로퍼티가 있다는 사실을 알 수 있음 그렇기에 우리는 Cat, Dog 또는 둘 다를 할당할 수 있음
유니온 타입 (|)에 사용된 값이 꼭 유니온을 구성하는 타입 중 하나일 필요는 없으며 양쪽 모두에 속할 수 있다.
그렇면 CatAndDog에 관련해서 무엇을 알고 있는가? 만능 하이브리드 슈퍼 애완견묘는 name을 가졌을 뿐 아니라 purr, bark, wag를 다 할 수 있다
실전에서는 대개 인터섹션보다 유니온을 자주 사용함
자바스크립트 처럼 타입스크립트 배열도 연결, 푸시, 검색, 슬라이스 등을 지원하는 특별한 객체다
타입스크립트는 T[ ]와 Array< T > 라는 두 가지 배열 문법을 지원함
대개는 배열을 동형으로 만들기 위해 배열의 모든 항목이 같은 타입을 갖도록 설계하려 노력함
두 가지의 타입을 가진 배열에 number이면 *3을 해주고 그게 아니라면 대문자로 바꾸어줌
객체와 마찬가지로 const라고 했더라도 타입스크립트는 타입을 더 좁게 추론하지 않음 따라서 d와 e 배열 모두 number | string으로 추론함
g는 특별한 상황으로 빈 배열로 초기화 하면 타입스크립트는 배열의 요소 타입을 알 수 없으므로 any일 것으로 추측함
튜플은 배열의 서브타입으로서 튜플은 길이가 고정되어있고 각 인덱스의 타입이 알려진 배열의 일종
다른 타입과 달리 튜플은 선언할 때 타입을 명시해야함 자바스크립트에서 배열과 튜플에 같은 문법 (대괄호)를 사용하는데 타입스크립트에서는 대괄호를 배열 타입으로 추론하기 떄문
튜플은 선택형 요소도 지원함
객체 타입과 마찬가지로 ?는 '선택형'을 뜻함
또한, 튜플의 최소 길이를 갖도록할 땐 rest문법을 쓸 수 있음
튜플은 이형(다른) 배열을 안전하게 관리할 뿐 아니라 배열 타입의 길이도 조절함
순수 배열에 비해 안정성을 높일 수 있으므로 튜플 사용을 권장함
일반 배열은 가변인 반면 상황에 따라선 불변인 배열이 필요할 수도 있다
타입스크립트는 readonly 배열 타입을 기본으로 지원하므로 이를 이용해 불변 배열을 만들 수 있음
읽기 전용 배열은 일반 배열과 같지만 내용을 갱신할 수 없다는 점만 다름
읽기 전용 배열을 갱신하려면 .push .splice처럼 내용을 바꾸는 동작 대신 .concat .slice 같이 내용을 바꾸지 않는 메서드를 사용해야 함
타입스크립트는 Array처럼 읽기 전용 배열과 튜플을 만드는 긴 형태의 선언 방법을 지원
읽기 전용 배열은 바꿀 수 없으므로 코드를 쉽게 이해할 수 있는 장점이 있지만 결국 자바스크립트 배열임은 바뀌지 않으므로 추후 스프레드나 .slice로 바꿀려하면 응용 프로그램의 성능이 느려질 수 있음
작은 배열에서는 이런 오버헤드가 사소해 보일 수 있지만 큰 배열에서는 눈에 띄게 큰 성능 저하를 일으킬 수 있다.
타입스크립트에서 undefined 값의 타입은 오직 undefined 뿐이고 null 값의 타입은 null뿐이라는 점에서 특별한 타입임
undefined : 아직 정의하지 않았음을 의미
null : 값이 없다는 의미 (값을 계산하려 하면 에러)
void : 명시적으로 아무것도 반환하지 않는 함수의 반환 타입
never : 절대 반환하지 않는 (예외를 던지거나 영원히 실행되는) 함수 타입)
unknown이 모든 타입의 상위 타입이라면 never는 모든 타입의 서브타입
즉, 모든 타입에 never를 할당할 수 있으며 never 값은 어디서든 안전하게 사용할 수 있음 (단, 그저 이론적인 사실)
열거형 (enum)은 해당 타입으로 사용할 수 있는 값을 열거하는 기법
열거형은 키를 값에 할당하는 순서가 없는 자료구조 -> 키가 컴파일 타임에 고정된 객체
따라서, 타입스크립트는 키에 접근할 때 주어진 키가 실제 존재하는지 확인 가능
열거형의 이름은 단수명사로 쓰고, 첫 문자는 대문자로 하는 것이 관례
더 안전한 열거형 타입 const enum을 이용하면 타입스크립트가 이런 안전하지 않은 작업을 막도록 만들 수 있음
const enum은 기본적으로 아무 자바스크립트도 생성하지 않고 그 대신 필요한 곳에 열거형 멤버의 값을 채워넣음
TSC 플래그 : preserveConstEnums
누군가의 타입스크립트 코드에 정의된 const enum을 가져왔을 땐 이 채워넣기 기능이 문제를 일으킬 수 있으므로 const enum을 사용할 때는 채워넣기 기능을 되도록 피해야하며 여러분이 제어할 수 있는 타입스크립트 프로그램에서만 사용해야함
NPM으로 배포하거나 라이브러리로 제공할 프로그램에서는 const enum을 사용하면 안 됨
이런식으로 선언만 되어있다면 숫자로 채워지는 바람에 숫자도 가능해져버림
그렇기에 문자열 값을 갖는 열거형을 통해 해결 가능
결과적으로, 숫자 값을 받는 열거형은 전체 열거형의 안전성을 해칠 수 있음
타입스크립트가 값의 타입을 추론하도록 하거나 값의 타입을 명시 가능
let과 var를 사용하면 일반적인 타입
const를 이용하면 더 구체적인 타입을 추론
구체적 타입은 보통 일반 타입의 서브타임