[React] TypeScript 자료형

hodu·2023년 4월 17일
0

React

목록 보기
2/2
post-thumbnail

테스트 사이트 : https://www.typescriptlang.org/play?#code/Q

TypeScript과 JavaScript 차이

TypeScriptJavaScript
staticdynamics
개발 도중, 에러 확인 가능런타임 할 때가 돼서야 에러 확인 가능
//javascript
function add(n1, n2) {
  if (typeof n1 !== "number" || typeof n2 !== "number") {
    throw new Error("Incorrect input!"); // 런타임시 에러를 감지
  }
  return n1 + n2;
}

const result = add(39, 28);

// typescript
function add1(n1: number, n2: number) {
  // 개발 환경에서 에러를 체크해주기 때문에 런타임시 에러 감지를 위한 코드를 작성할 필요가 없다.
  return n1 + n2;
}

ECMA 표준에 따른 기본 자료형타입스크립트 추가 자료형
Boolean, Number, String, Null, Undefined, Symbol, Array: objectAny, Void, Never, Unknown, Enum, Tuple : object




PRIMITIVE TYPE

Object와 Reference가 아닌 실제 값을 저장하는 자료형.
ex) Boolean / Number / String / Null / Undefined / Symbol

리터럴 표기로 타입을 나타낼 수 있다.

let a = "Hi";

new 생성자를 이용해 wrapper object로 만들어 참조형 자료들처럼 사용할 수 있다.
이렇게 만들어진 wrapper object는 primitive type이 아니다.

const str = "hodu";
const strObj = new String(str);	// 문자열 객체 생성

str.length;	// 리터럴 값은 내부적으로 wrapper object 를 생성한 후, length Property를 참조한다.
str == strObj;	// 동등 연산자는 리터럴 값과 해당 wrapper object를 동일하게 본다.
str === strObj;	// 일치 연산자는 리터럴 값과 해당 wrapper object를 구별한다.

typeof str;	// string 타입
typeof strObj;	// object 타입

wrapper object는 타입으로 사용해서는 안되며, primitive type(number, string, boolean, symbol)과 참조 자료형(Number, String, Boolean, Symbol)은 서로 다른 자료형이다.



TypeScript Type

1. boolean

let isDone: boolean = false;
isDone = true;
console.log(typeof isDone);	// boolean

let isOk: boolean = true;
let isNotOk: boolean = new Boolean(true);	// error, boolean 타입과 wrapper object Boolean은 다르기 때문이다.



2. number

let decimal: number = 6;

// 2진수 8진수 16진수도 사용 가능하다.
let hex: number = 0xf00d;	// 16진수
let binary: number = 0b1010;	// 2진수
let octal: number = 0o744;	// 8진수

// NaN은 number 타입에 해당한다.
let notANumber: number = NaN;

// 천 단위로 _를 사용해 끊어 표기가 가능하다.
let underScore: number = 1_000_000;



3. string

let name: string = "hodu";
name = "angel";

let fullName: string = "hodu angel";
let age: number = 10;
let sentence: string = `Hello, i am ${name}, and i'm ${age} years old`;



4. symbol

debugging 시 참고할 description으로 사용되며, 특별한 의미를 가지진 않는다.
wrapper object나 메서드가 아닌 데이터이다.

// 타입스크립트에서 Symbol타입이 인식이 안될 땐 tsconfig.json파일에서 "lib" : [], 주석을 해제하고 ["ES2015", "DOM"]을 추가한다.
console.log(Symbol("foo")); // Symbol은 String이나 Number와 같은 래퍼 객체가 아니다.

console.log(Symbol("foo") === Symbol("foo")); //false

Symbol은 primitive type의 값을 담아서 사용한다.
해당 값을 고유하고 수정 불가능한 값으로 만들어준다.
접근을 제어하는데 많이 쓰인다.

const sym = Symbol();
const obj = {
	[sym]: "value",
};
// obj.sym 또는 obj["sym"] 으로는 접근할 수 없다
console.log(obj[sym]); // "value"



5. undefined 와 null

undefined와 null은 각, undefined 및 null 이라는 타입을 가진다.
void와 마찬가지로 그 자체로는 유용하지 않다. 둘다 소문자만 존재한다.

let u: undefined = undefined;
let n: null = null;

따로 설정하지 않는 이상, undefined와 null은 모든 다른 타입의 서브 타입으로 존재한다.
number 타입 변수에 null이나 undefined를 할당 할 수 있다는 의미이다.

하지만 데이터의 정확도와 안정성을 높이기 위해서 이러한 상황을 방지하는 것이 좋다.
tsconfig.js파일에서 "strict": true, 또는 --strictNullChecks 주석을 해제하면 null은 자기 자신에게만, undefined는 자기 자신과 void에만 할당이 가능하다.

하지만 이렇게 strict한 상황에서 코딩하는 것은 매우 힘들다. 이 경우 union type을 활용해 null과 undefined 할당을 가능하게 할 수 있다.

let name: number = undefined;	// error
let u: undefined = null;	// error
let v: void = undefined	// void는 타입이고, 값으로는 존재할 수 없다. void에는 undefined 할당이 가능하다.

// union type으로 설정하여, null과 string을 모두 사용할 수 있게 한다.
let union: string | null = null;
union = "hodu";



6. object

TypeScript 에서 object는 "primitive type이 아닌 것"을 나타내고 싶을 때 사용하는 타입이다.
즉, 원시 자료형을 제외한 모든 자료형을 의미한다.

const person1 = { name: "hodu", age: 10 };
// person1은 object 타입이 아니다.
console.log(typeof person1);	// "{name: string, age: number}" type

const person2 = Object.create({ name: "Mark", age: 39 }); // 괄호 안에는 객체 형태 또는 null을 넣을 수 있다.
const person3 = Object.create(39); // error
const person4 = Object.create([]); // 배열도 가능하다.
const person5 = Object.create(function () {}); // 함수도 가능하다.

// 함수는 주로 아래와 같이 사용한다.
declare function create(o: object | null): void;
create({ prop: 0 }); //ok
create(null); //ok
create(42); // error
create("string"); // error
create(false); // error
create(undefined); // error



7. Array

let list: number[] = [1, 2, 3];
// 리액트와 사용할 때 jsx언어와 충돌할 수 있어서 첫번째 표현식을 권장한다.
let list2: Array<number> = [1, 2, 3];
// union type 지정이 가능하다.
let list3: (number | string)[] = [1, 2, 3, "4"];



8. tuple

let x: [string, number];

x = ["hodu", 10];
x = [10, "hodu"];	// error

const person: [string, number] = ["hodu", 10];
const [one, two, three] = person;
// one은 string, two는 number
// 지정한 tuple의 길이를 초과했기 때문에 three는 error.



9. any

any 타입의 변수에는 어떤 타입의 값도 올 수 있다. 타입 시스템의 안정성을 위해 any 사용은 권장되지 않는다.

function returnAny(message: any): any {
	// 이 함수의 리턴 값은 어떤 값도 될 수 있다.
  console.log(message);
}

// any 타입은 전파된다.
function leakingAny(obj: any){
	const a = obj.num;
  	const b = a + 1;
  	return b;
}

// function 안 변수들의 타입은 모두 any이다.
const c = leakingAny({ num: 0 });

function leakingAny(obj: any) {
  const a: number = obj.num; // 이렇게 누수를 막으면 이 이후에 변수들의 타입은 number가 된다.
  const b = a + 1;
  return b;
}



10. unknown

모르는 변수의 타입을 묘사해야 할 때(ex. 동적 컨텐츠 값을 받아와야 할 때) 컴파일러와 미래의 코드를 읽는 사람에게 이 변수가 어떤 타입도 될 수 있음을 알려주는 unknown type을 활용한다.

이 때 런타임 과정에서 타입가드인 if문을 통해 unknown 타입을 한정시켜 사용한다.

declare const maybe: unknown;
const aNumber: number = maybe;	// error

만일 maybe가 any였다면 여기서 error가 발생하지 않는다. 그렇게 되면 개발자가 예상치 못한 곳에서 실수할 가능성이 늘어난다.

unknown은 컴파일러가 타입을 추론할 수 있도록 타입의 유형을 좁히거나 타입을 확정해주지 않으면 다른 곳에 할당할 수 없고, 사용할 수 없다.

// 타입가드
if(maybe === true) {
	const aBoolean: boolean = maybe;	// maybe가 true 일 때만 작동하기 때문에 여기서 maybe는 boolean 타입으로 에러가 발생하지 않는다.
  const aString: string = maybe;	// error, maybe는 boolean 타입이기 때문에 string 타입과 맞지 않아 에러가 발생한다.
}

// maybe의 타입이 string 일 때만 작동하기 때문에 에러가 발생하지 않는다.
if (typeof maybe === "string") {
  const aString: string = maybe; 
}

any 대신 unknown을 활용하면 runtime error를 줄일 수 있다. (타입가드 덕분에)


11. never

never 타입은 모든 타입의 subType이며, 모든 타입에 할당할 수 있다. 하지만 never에는 그 어떤 것도 할당할 수 없다.

어떤 값도 올 수 있는 any조차도 never에 할당할 수 없다.
주로 잘못된 타입을 넣는 실수를 방지하고자 할 때 사용한다.

function error(message: string): never {
  throw new Error(message);
  //return 값이 없기 때문에 never를 지정할 수 있다.
}

function fail() {
  // 리턴하고 있는 에러 함수에 리턴 타입이 never이기 때문에 이 함수의 return 타입도 never이다
  return error("failed");
}

function infiniteLoop(): never {
  while (true) {}
  // 출구 없는 while 문으로 return 값이 없어 return type은 never 이다.
}

let a: string = "hello";
if (typeof a !== "string") {
  a; // 여기서 a의 타입은 never이다.
}

declare const b: string | number;
if (typeof b !== "string") {
  b; // 여기서 b의 타입은 number이다.
}



12. void

function returnVoid(message: string) {
  // return이 없는 함수의 경우 기본 타입은 void
  console.log(message);
}

const r = returnVoid("리턴이 없다."); // 여기서 r의 타입도 void가 된다.
const r: undefined = returnVoid("리턴이 없다."); // error

function returnVoid(message: string): void {
  // void가 지정된 함수는 해당 함수의 리턴값을 사용하지 않겠다는 명시적 표현이다.
  console.log(message);
  return undefined; // 유일하게 undefined만 리턴할 수 있다.
}





참고 문서 :
https://velog.io/@pca0046/TIL-47.-%ED%83%80%EC%9E%85%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%EC%9E%90%EB%A3%8C%ED%98%95-%ED%83%80%EC%9E%85

https://medium.com/sjk5766/es-6-symbol-%EC%9D%B4%EB%9E%80-48c2ad5b054c

profile
Flutter developer

0개의 댓글