원시 타입(primitive type)은 글자 · 수 · 참·거짓 같은 기본 값의 타입입니다. string · number · boolean에 값이 없음을 나타내는 null · undefined까지 다섯이고, 검사기는 이 다섯을 서로 다른 값의 모음으로 봅니다.
자바스크립트는 글자가 올 자리에 null이 와도 그 줄을 조용히 지나가고, 그 값을 글자처럼 쓰는 줄에서야 TypeError로 멈춥니다. 검사기는 string 자리에 null을 넣는 줄을 실행하기 전에 막습니다.
이 단원을 이미 안다면 단원 연습 문제의 진단 문항부터 풀고 틀린 레슨만 보세요.
1다섯 타입은 서로 다른 값의 모음이다
타입은 그 자리에 올 수 있는 값의 모음입니다(검사 규칙 2). 원시 타입 다섯의 모음에는 이런 값이 듭니다.
| 타입 | 모음에 드는 값 | 예 |
|---|---|---|
string | 글자 | '라테' · '' |
number | 수 — 정수와 소수가 한 타입 | 4500 · 0.5 · NaN |
boolean | 참·거짓 | true · false |
null | null 하나 | null |
undefined | undefined 하나 | undefined |
null과 undefined는 값의 이름이면서, 그 값 하나만 드는 모음의 이름이기도 합니다. 타입 이름은 다섯 모두 소문자입니다.
대입하는 줄마다 검사기는 오른쪽 값이 선언 타입 모음에 드는지 봅니다. 따옴표 안의 '4500' · 'true'는 글자라서 number · boolean 모음에 들지 않습니다.
let price: number = 4500;
let hot: boolean = true;
price = '4500';
hot = 'true';
main.ts(3,1): error TS2322: Type 'string' is not assignable to type 'number'.main.ts(4,1): error TS2322: Type 'string' is not assignable to type 'boolean'.첫 오류는 'string 타입은 number 타입에 넣을 수 없다', 둘째는 boolean 자리에 글자 값을 넣었다는 뜻입니다. 검사기는 3번 줄에서 멈추지 않고 4번 줄까지 읽어 오류를 둘 다 보입니다.
원시 타입에는 이 다섯 말고 bigint · symbol도 있지만, 이 과목에서는 쓰지 않습니다.
2typeof가 내는 글자와 타입 이름
JS 다시 보기: typeof는 값의 종류를 'string' · 'number' 같은 글자로 돌려주고, typeof null은 'object'입니다(JS '수·글자·불리언과 typeof').
타입 이름은 검사기가 쓰는 말이고, typeof가 내는 글자는 실행할 때 자바스크립트가 내는 값입니다.
console.log(typeof '라테');
console.log(typeof 4500);
console.log(typeof true);
console.log(typeof null);
console.log(typeof undefined);
string
number
boolean
object
undefined다섯 가운데 넷은 타입 이름과 글자가 같고, null 하나만 타입은 null인데 글자는 'object'입니다. 자바스크립트 초기의 실수가 그대로 굳은 것이고, 4단원의 좁히기 — typeof와 타입 추적 표에서 다시 만납니다.
3null과 undefined는 다른 모음에 들지 않는다
null과 undefined는 string · number · boolean 모음에 들지 않습니다.
메모가 없는 주문이라 memo를 null에 붙이면, 검사기는 그 줄을 막습니다.
let item: string = '라테';
let memo: string = null;
main.ts(2,5): error TS2322: Type 'null' is not assignable to type 'string'.'null 타입은 string 타입에 넣을 수 없다', 곧 string 자리에 null을 넣었다는 뜻입니다. undefined도 같아서, 2번 줄을 let memo: string = undefined;로 바꿔도 같은 TS2322로 막힙니다.
그러면 둘 다 '값이 없다'는 뜻인 null과 undefined끼리는 서로의 자리에 넣을 수 있을까요? 아래 2번 줄은 검사를 지나갈까요? 답을 정한 뒤 펼쳐 보세요.
let left: undefined = undefined;
let gone: undefined = null;
검사 결과 보기
main.ts(2,5): error TS2322: Type 'null' is not assignable to type 'undefined'.예상과 다르면 그곳이 배울 곳입니다.
2번 줄이 막힙니다. null과 undefined는 값이 하나씩만 드는 서로 다른 모음이라, undefined 자리에 null이 들지 않습니다(검사 규칙 2).
값이 없을 수도 있는 이름이면 선언 타입을 string | null처럼 두 모음을 합쳐 적습니다. |는 '이거나'라는 뜻이고, 4단원의 유니언 레슨에서 배웁니다.
예제
주문 한 잔에 얼음을 넣을지 정하는 코드입니다. iced를 boolean으로 적었는데, 값을 따옴표 안의 글자 'false'로 썼습니다.
JS 다시 보기: 빈 문자열 ''이 아닌 글자는 조건 자리에서 참으로 칩니다(JS '참 같은 값과 ??').
let iced: boolean = 'false';
if (iced) {
console.log('얼음 넣기');
} else {
console.log('얼음 빼기');
}
main.ts(1,5): error TS2322: Type 'string' is not assignable to type 'boolean'.얼음 넣기검사기는 boolean 자리에 글자 값을 넣은 1번 줄을 막습니다. 그래도 Node는 돌립니다(검사 규칙 1). 글자 'false'는 빈 문자열이 아니라서 조건 자리에서 참이고, 얼음을 빼려던 주문에 '얼음 넣기'가 찍힙니다.
자바스크립트라면 오류 없이 틀렸을 코드를 검사기가 먼저 잡은 것입니다. 따옴표를 빼고 false로 쓰면 검사를 지나고 '얼음 빼기'가 찍힙니다.
자주 틀리는 곳
틀린 생각: 타입 이름은 String처럼 대문자로 써도 string과 같다.
자바스크립트에 String() 함수가 있어서 타입 이름도 대문자로 쓰기 쉽습니다. 그러나 String은 다른 타입이라, 그 이름을 string 자리로 넘기는 줄에서 막힙니다.
let size: String = 'tall';
let cup: string = size;
main.ts(2,5): error TS2322: Type 'String' is not assignable to type 'string'. 'string' is a primitive, but 'String' is a wrapper object. Prefer using 'string' when possible.1번 줄은 지나가고 2번 줄이 막힙니다. 들여 쓴 줄이 까닭입니다 — 'string은 원시 타입이고 String은 값을 감싼 객체(wrapper object)다. 되도록 string을 써라.'
맞는 규칙: 대문자 String · Number · Boolean은 원시 값을 감싼 객체의 타입이라 원시 타입과 다른 모음입니다. 원시 타입의 이름은 소문자로 씁니다.
틀린 생각: null은 어느 타입 자리에나 넣을 수 있다.
타입스크립트 5.9까지는 설정이 없으면 strict가 꺼져 있었고, 그때는 null이 string 자리에도 들어갔습니다. 6.0부터는 설정 없이도 strict가 켜져서 막힙니다.
3절 코드 끝에 console.log(memo.length);를 더해 돌리면 null의 length를 읽다가 TypeError로 멈춥니다. 검사기는 같은 실수를 null을 넣는 줄에서 먼저 잡습니다.
맞는 규칙: strict에서는 null · undefined가 string · number · boolean 모음에 들지 않습니다. 없을 수 있는 값이면 string | null처럼 선언 타입에 적습니다(검사 규칙 2).
틀린 생각: typeof로 null을 고르려면 'null'과 견주면 된다.
타입 이름이 null이라서 typeof도 'null'을 낼 것 같습니다. 그러나 typeof는 'null'을 내는 일이 없어서, 검사기가 이 비교를 막습니다.
const memo = null;
if (typeof memo === 'null') {
console.log('메모 없음');
} else {
console.log('메모 있음');
}
main.ts(2,5): error TS2367: This comparison appears to be unintentional because the types '"bigint" | "boolean" | "function" | "number" | "object" | "string" | "symbol" | "undefined"' and '"null"' have no overlap.메모 있음TS2367은 '이 비교는 뜻한 것이 아닌 것 같다 — 두 타입에 겹치는 값이 없다'는 뜻입니다. 왼쪽에 줄지은 따옴표 글자 여덟은 typeof가 낼 수 있는 글자 모두이고, 그 가운데 'null'이 없습니다.
Node로 돌리면 이 조건은 늘 거짓이라, memo가 null인데도 '메모 있음'이 찍힙니다.
맞는 규칙: typeof null은 'object'입니다. null인지는 memo === null처럼 값을 바로 견주어 알아보고, 자세한 것은 4단원의 null·undefined 거르기에서 배웁니다.
확인 문제
1. 예제의 1번 줄을 let iced: boolean = null;로 바꿨습니다. 검사는 지나갈까요? 지나가지 못하면 몇 번 줄인가요? Node로 돌리면 무엇이 찍힐까요?
let iced: boolean = null;
if (iced) {
console.log('얼음 넣기');
} else {
console.log('얼음 빼기');
}
힌트
검사는 1번 줄 오른쪽 값이 어느 모음에 드는지로, 실행은 그 값이 조건 자리에서 참인지 거짓인지로 생각합니다.
정답
main.ts(1,5): error TS2322: Type 'null' is not assignable to type 'boolean'.얼음 빼기1번 줄이 막힙니다. null은 boolean 모음에 들지 않습니다.
그래도 Node는 돌리고, null은 조건 자리에서 거짓이라 '얼음 빼기'가 찍힙니다.
흔한 오답은 '실행되지 않는다'입니다. 검사 오류가 있으면 Node도 돌지 않는다고 본 것입니다(검사 오류가 실행을 막는다는 생각). Node는 검사하지 않고 타입을 지워 돌립니다.
2. 검사를 지나도록 빈칸에 타입 이름을 쓰세요.
let item: ____ = '녹차';
let price: ____ = 3500;
let hot: ____ = false;
let coupon: ____ = null;
힌트
값마다 1절 표의 다섯 모음 가운데 어느 모음에 드는지 찾습니다.
정답
차례로 string · number · boolean · null입니다.
let item: string = '녹차';
let price: number = 3500;
let hot: boolean = false;
let coupon: null = null;다르게 써도 되는 곳: 대문자 String · Number · Boolean도 이 네 줄은 지나가지만, 그 이름을 소문자 타입 자리로 넘기는 줄에서 막힙니다(자주 틀리는 곳 첫째). 소문자로 씁니다.
흔한 오답은 넷째 빈칸의 undefined입니다. null과 undefined는 서로 다른 모음이라 TS2322로 막힙니다.
3. 하루 걸음 수가 목표를 넘었는지 찍는 코드입니다. 검사 결과와 Node로 돌린 실행 결과를 각각 쓰세요.
let steps: number = 8000;
let goal: number = undefined;
console.log(steps >= goal);
힌트
검사 결과는 1절의 모음 표로, 실행 결과는 자바스크립트가 수와 undefined를 견줄 때 무엇을 내는지로 생각합니다.
정답
main.ts(2,5): error TS2322: Type 'undefined' is not assignable to type 'number'.false2번 줄이 막힙니다. number 자리에 undefined를 넣었다는 뜻입니다.
Node는 그래도 돌고, 수와 undefined를 견주면 오류 없이 false입니다. 목표가 정해지지 않았는데 '못 넘었다'로 찍히는, 오류 없이 틀린 결과입니다.
흔한 오답은 '실행되지 않는다'입니다(검사 오류가 실행을 막는다는 생각). 검사 결과와 실행 결과는 따로입니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
3절 첫 코드(두 줄)를 main.ts로 저장해 npx tsc로 검사합니다. 그다음 2번 줄의 null을 '없음'으로 바꾸면 검사 결과가 어떻게 될지 먼저 적고, 다시 검사해 맞춰 봅니다.
터미널에는 같은 오류가 main.ts:2:5 - error TS2322처럼 자리를 적는 꼴만 다르게 나옵니다. 검사하고 돌리는 법은 내 컴퓨터에서 검사하고 돌리기에 있습니다.