자바스크립트에서 온 타입을 Primitive type
이라고 한다.
오브젝트와 레퍼런스 형태가 아닌 실제 값을 저장하는 자료형.
➡ 오브젝트
혹은 레퍼런스
라고 불리는 이 형태는 실제 값을 저장하지 않는다. 실제 값에 대한 정보를 저장해놓은 것이다.
ex)문자열 - string, 숫자 - number 등
Primitive 형의 내장함수를 사용하는 것은 자바스크립트 처리 방식 때문이다.
(ES2015) 기준 6가지
1. boolean
2. number
3. string
4. symbol(ES2015)
5. null
6. undefined
let name = 'kim'
name.toString();
35; // number 리터럴
'kim' // string 리터럴
true // boolean 리터럴
//object 리터럴
{
name: 'kim',
age: 32
}
래퍼객체(Wrapper Object)
로 만들 수 있다.new
해서 만들 수 있다.)new Boolean(false) // typeof new Boolean(false) : 'object'
new String('world') // typeof new String('world') : 'object'
new Number(42) // typeof new Number(42) : 'object'
하지만 자바스크립트에서는 이런식으로 래퍼 객체(Wrapper Object)를 만드는 것을 추천하지 않는다.
그 이유는 몇몇 상황에서 혼동을 야기하기 때문이다.console.log( typeof 0 ); // 'number' console.log( typeof new Number(0) ); // "object"
위와 같이 래퍼객체를 new 키워드를 통해 직접 만들어 데이터를 할당한다면 이것은 명시적인 객체가 되어버린다.
래퍼 객체는 원시값을 가볍게 유지하며 사용하기 위함이기 때문에 의도적으로 만들어 사용하는 것은
필요하지 않는 이상 추천되지 않는다.
또한, 트루시한 값과 펄시한값을 구분하는데에 있어 원치 않는 결과를 도출한다.if(0) { // 0은 펄시한 값이라 false로 조건을 판단 ... } let numObj = new Number(0); if(numObj) { // 오브젝트는 논리 평가시 항상 참을 반환한다. ... }
위와 같은 여러가지 상황 때문에
new
를 이용한 객체를 권장하지 않는다.
하지만new
를 사용하지 않고 그냥Number(str)
처럼 묶어주는 것은 안의 인자를 숫자형 원시타입으로
만들어 주기만 하기 때문에 아주 유용하다.
✏️ true 또는 false를 나타내는 자료형
let isDone: boolean = false;
// Primitive Type하기 => boolean 소문자
isDone = true;
console.log(typeof isDone) // boolean
✏️ Javascript와 같이 Typescript의 모든 숫자는 부동 소수점 값
let decimal:number = 6; // 10진수 사용가능
let hex:number = 0xf00d; // 16진수 사용가능
let binary:number = 0b1010; // 2진수 사용가능
let octal:number = 0o744; // 8진수 사용가능
let notNumber:number = NaN; // NaN을 할당해도 전혀 문제 없다, NaN은 숫자의 한 형태이기 때문이다.
let underscoreNum:number = 1_000_000; // _를 이용해서도 사용가능하다, 1_000_000 = 1,000,000 = 백만
✏️ 텍스트 형식을 참조하기 위해 "String"형식을 사용
"
큰따옴표나, '
작은따옴표를 사용한다.let myName:string = "hosik";
myName = "kim";
+
기호를 사용하여 문자열을 더해주었다.``
기호로 둘러쌓여있다.${expr}
와 같은 형태로 표현되어진다.let fullName: string = "hosik"
let age:number = 20;
let sentence:string = `Hello My Name is ${fullNmae}.
I'll be ${age + 1} years old in 7 months`
//console.log(sentence)
// Hello My Name is hosik.
// I'll be 33 years old in 7 months
✏️ Symbol은 고유한 데이터로, 여러개의 Symbol에 동일한 description을 넣어도 각 다른 존재로 인식된다.
자바스크립트로 더 알아보자면
const a = Symbol("id"); const b = Symbol("id"); console.log(a == b); // false
같은 문자열을 넣었는데 결과값이 fasle로 나오는 이유는?
➡ Symbol은 고유한 존재이기 때문에 문자열이 같아도 영향을 미치지 않기 때문이다.
Typescript로 알아보면 그전에 tsconfig.json
에서 설정해주어야한다.
"lib" : [
"ES2015",
"DOM"
]
Typescript로 작성하면 아래의 코드와 같다.
console.log(Symbol('foo') === Symbol('foo')); // false
const sym = Symbol();
const obj = {
[name]: "val"
};
console.log(obj[name]) // "val"
// 접근을 막거나, 접근이 필요한 경우에만 사용
만약
obj객체
에name
속성 외에 다른 속성이 무수히 있다고 가정하고
협업을 하다가 한 팀원이obj객체
에name
속성이 있는지 모르고
또name
속성을 추가해서 덮어씌어버린다면 코드가 오류 나버린다!
이 속성 값은 건들지 않게 하고 싶은 경우Symbol
을 사용한다.
같은 속성 이름으로 값을 추가하더라도Symbol
은 다른 존재로 인식 하기 때문에 충돌이 없기 때문이다.
string
값으로 속성을 추가 하면 바로 덮어 씌어버리기 때문에,Symbol
을 사용해야한다.
이것이string
과symbol
의 차이
➡즉, 다른 사람과 협업할 때, 중요한 속성 값을 보호하기 위함이다.
✏️ 값이 없다는 의미
❗️null은 Object자료형을 가지고 있고, undefined는 자료형이 없다.
null
➡ 변수를 선언하고 빈 값을 할당한 상태(빈 객체)
undefined
➡ 변수를 선언하고 값을 할당하지 않은 상태
즉,undefined
는 자료형이 없는 상태이므로
typeof
를 통해 자료형을 확인해보면null
은object
로,
undefined
는undefined
로 출력되는 것을 확인할 수 있다.
// 이 변수들에 할당할 수 있는 것들은 거의 없다.
let u: undefined = undefiend;
let n: null = null;
하지만 tsconfig
파일 설정을 한다면 달라진다.
즉, null 과 undefined를 할당할 수 있다는 의미
null 과 undefined는 다른 모든 타입에 서브타입으로 존재한다.
만약 number에 number형이 아니라 null을 넣더라도, 사용할 수 있다는 의미이다.
null과 undefined를 할당할 수 있게 하려면, union type
을 사용해야한다.
하지만 컴파일 옵션
즉, ts파일을 ➡ js파일로 변경하는 옵션
에서 strictNullChecks
옵션을 사용하면서,
컴파일을 한다면 그 때는 null
과 undefined
는 모든 하위 탑에 존재하지 않게 된다.
__+) 즉, 컴파일 옵션에서
strictNullChecks
를 사용하면, null과 undefined는 void나 자기 자신에게만 할당할 수 있다.
❗️void에 유일하게 undefined를 할당할 수 있다. null은 안된다.
let myName: string = null;
// 오류가 발생한다.
오류를 없애기 위해선 tsconfig.json
에서 "strict": "true"
를 주석해주어야한다.
➡ 하지만 위 방법은 좋은 방법은 아니다.
union type을 이용해야한다.
➡ |
이렇게 작성하는 타입이다.
ex)let union: string | null | undefined = 'hosik';
➡ 합집합과 같은 의미이다.
// let u : undefined = null; // (X)
let v: void = undefined; // (O)
// void는 타입으로만 존재하기 때문에
// let v: void = void; 로 넣을 수 없다.
// undefined는 타입이기도 하지만 값이기 때문에 넣을 수 있다.
// null은 안된다.
let union: string | null | undefined = 'hosik';
여기까지가
Primitive Types
는 끝이다.
✏️객체: 이름(name)과 값(value)으로 구성된 프로퍼티(property)의 정렬되지 않은 집합
primitive Type
과 다르게 직접 값을 가지고 있지 않고, 그 값을 가리키는 정보를 가지고 있는 성질을 가지고 있다.// Created by object literal
const person1 = {name: 'hosik', age: 32};
// person1 is not "object" type
// 타입스크립트에선 person1은 Object 타입이 아니다.
// person1 is "{name: 'hosik', age: 32}" type
// person1은 "{name: 'hosik', age: 32}" 이러한 타입으로 나온다.
// Created by object.create
// Object: 소문자가 아닌 대문자 오브젝트
// Object: 전역객체, 내장전역객체 - runtime에 제공되는 미리 준비된 것
// 여기서 Object는 primitive Type이 아닌 것
// 그래서 인자로 들어오는 타입은 오브젝트 or null인 합집합으로 이루어져 있다.
const person2 = Object.create({name: 'hosik', age: 32});
primitive Type
을 제외하고 올 수 있는 모든 것을Ojbect
라고 한다.
primitive Type
: number, string, boolean, bigint, symbol, null or undefined
예를 들어{}
객체 형태 또는[]
배열 형태가 있다.
✏️ 같은 타입의 요소들을 모아놓은 자료형
let list: number[] = [1, 2, 3]; // 이 방식이 더 많이 사용된다.
let list: Array<number> = [1, 2, 3];
// Array<number>는 js나 ts에서 충돌 날 위험이 있기 때문이다.
let list: (number | string)[] = [1, 2, 3, "4"];
// union으로 위에처럼 가능하다.
// 하지만 ["Mark", 39]의 자료처럼 첫번째는 String, 두번째는 Number의 경우에는
// Array가 아닌 Tuple을 사용한다.
✏️ 배열과 비슷하지만, 자료형에 대한 순서가 있을 때 사용되는 자료형
["Mark", 39]
의 자료처럼 첫번째는String
, 두번째는Number
의 경우에는Array
가 아닌Tuple
을 사용한다.
let x: [string, number];
x = ["hosik", 32]; // 순서와 타입, 길이 모두 일치해야한다.
// x = [32, "hosik"] // Error => 순서가 다르기 때문에
// x[2]; // Error => 2번째 인덱스에는 아무것(undefined)도 없기 때문에
const person: [string, number] = ["hosik", 32];
const [] = person; // destructuring (분해할당)
// person에 있는 요소를 가지고 나와서 [] 변수 안에 넣는다.
// 순서가 중요하다 => [first, second]
const [first, second] = person;
✏️ 어떤 것이나 된다는 의미를 가진 타입
❗️즉, Any는 정확히 알고 써야한다.
function returnAny(message): any {
console.log(message);
};
const any1 = returnAny('리턴은 아무거나');
any1.toString(); // 타입에러 뜨지 않음 => any이기 때문이다.
noImpicitAny
let looselyTyped: any = {};
let d = looselyTyped.a.b.c.d;
// looselyTyped는 any이기에 .a.b.c로 타고 갈 경우에도 any로 지정이 된다.
// 그로 인해 오류가 발생하지 않는다.
function leakingAny(obj: any) {
// const a = obj.num; // a의 타입: any
const a: number = obj.num // a의 타입: number
const b = a + 1; // b의 타입 : any => b의 타입 : number
return b;
}
const c = leakingAny({ num : 0 });
// c.indexOf('0')
✏️Any가 가지고 있던 타입에 불안정한 요소를 주는 그러한 부분을 해소시키고자 나온 대체 자료형
any
라고 지정했었던 것declare const maybe: unknown;
// const aNumber: number = maybe; (x)
if(typeof maybe === 'number') { // typeof typeguard
const aNumber: number = maybe; // (o)
}
if(maybe === true) { // typeguard
const aBoolean: boolean = maybe; // (o)
// const aString: string = maybe; // (x)
}
if(typeof maybe === 'string') { // typeof typeguard
const aString: string = maybe; // (o)
// const aBoolean: boolean = maybe; // (x)
}
declare란?
변수, 상수, 함수, 또는 클래스가 어딘가에 이미 선언되어 있음을 알리는 모듈
Type Guard란?
컴파일러가 타입을 예측할 수 있도록 타입을 좁혀 주어서(narrowing) 좀 더 type safety함을 보장할 수 있는 것
✏️ 보통 return에서 사용된다.
function error(msg: string): never {
throw new Error(msg);
// throw를 하면 이 밑으로는 내려오지 않게 된다.
}
// never는 아무것도 리턴되지 않는다라는 의미
// return이나 함수의 body부분이 끝나지 않아야 한다.
function fail() {
return error('failed');
}
function infiniteLoop(): never {
while(true) {}
// while 밑으로 내려오지 않는다.
}
let a: string = 'hello';
if(typeof a !== 'string') {
// string이 아닌 것을 빼면 never
let b: never = a;
}
// 조건문 타입 추후에 알 예정이다.
type Indexable<T> = T extends string ? T & { [index: string]: any} : never;
type ObjectIndexable<T> = Indexable<{}>'
// T extends string: T가 만약에 String이면
// T & { [index: string]: any }:
// T를 [index: string]: any 이렇게 만들어서 보내고
// 아니라면 never라는 타입을 보내라는 뜻
// const b: Indexable<{}> = ''; // 오류 => never 타입
✏️ 어떤 타입도 가지고 있지 않는 빈 상태를 의미하는 자료형.
function returnVoid(message:string) {
console.log(message);
return;
}
const r = returnVoid("리턴이 없다"); // const r: void
function returnVoid(message: string): void {
console.log(message);
return undefined;
}