Typescript-1

HeumHeum2·2020년 5월 1일
0

TypeScript

velopert님의 블로그 글과 공식문서를 참고해 공부했습니다.
https://velog.io/@velopert/using-react-with-typescript
https://typescript-kr.github.io

JavaScript에서 변수선언 할 때, 어떠한 값을 대입해도 해당 값이 잘 들어가는 것을 볼 수 있습니다.

let test = 7;
test = 'hello world';
test = [1,2,3,4,5];
test = null;

Java를 하다 JavaScript를 접하니 String이나 int 같은 변수 선언으로 타입을 고정하는게 아닌 유동적으로 값을 할당할 수 있기에 편하게 다가왔습니다.

하지만 프로그래머가 실수로 숫자인줄 알고 비교했는데 문자열이여서 예상치 못한 결과 값이나, 에러가 생겼습니다.

또한, VS code에서 JavaScript를 사용 할 때 자동완성이나, IDE에서의 오류 확인이 제대로 되지 않아 컴파일을 한 뒤에 에러를 체크 할 수 있었습니다.
TypeScript를 사용하면 위의 문제를 말끔히 해결시켜줍니다.

사용이유

  1. IDE
    TypeScript를 사용하는 가장 큰 이유는 IDE가 아닐까 싶습니다. VS code는 마이크로소프트에서 개발했으며, TypeScript 또한 마이크로소프트에서 개발했습니다. 때문에 TypeScript의 자동완성 및 타입 체킹의 지원이 잘 되어있습니다.
    또한 컴포넌트를 사용하거나, 함수를 사용할 때 해당 파일을 직접 열어보지 않고도 어떤 props, 파라미터를 넣어줘야 하는지 마우스를 가져다 대면 확인 할 수 있는 장점이 있습니다.
  2. 실수를 줄일 수 있음
    오타 및 함수에 타입을 잘못 설정했다던지 이런 실수를 했을 때, 컴파일하기 전 에디터 단에서 알려주기 때문에 실수를 많이 줄일 수 있습니다.
  3. 협업 할 때 유용
    협업한 사람에게 직접 물어보지 않아도, 해당 컴포넌트나 함수를 IDE상에서 마우스를 올려보면 확인 할 수 있기 때문에 협업하는 사람에게 직접 물어보지 않아도 사용할 수 있습니다.

기본 타입

TypeScript에는 여러가지 기본 타입들이 있습니다.

불리언(Boolean)

boolean 값이라고 일컫는 참/거짓(true/false) 값입니다.

let isDone: boolean = false;

숫자(Number)

JavaScript처럼, TypeScript의 모든 숫자는 부동 소수 값입니다. 부동 소수에는 number라는 타입이 붙혀집니다. TypeScript는 16진수, 10진수 리터럴에 더불어, ECMAScript 2015에 소개된 2진수, 8진수 리터럴도 지원합니다.

let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

문자열(String)

텍스트 데이터 타입을 String으로 표현합니다. TypeScript도 큰 따옴표(")나 작은따옴표(')를 문자열 데이터를 감싸는데 사용합니다.

let color: string = "blue";
color = 'red';

또한 템플릿 문자열을 사용하면 여러 줄에 걸쳐 문자열을 작성할 수 있으며, 표현식을 포함시킬 수도 있습니다. 이 문자열은 백틱/백쿼트(`) 문자로 감싸지며, ${ expr}과 같은 형태로 표현식을 포함시킬 수 있습니다.

let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ fullName }.
I'll be ${ age + 1 } years old next month.`;

위는 아래 sentence선언과 동일합니다.

let sentence: string = "Hello, my name is " + fullName + ".\n\n"+
    "I'll be " + (age + 1) + " years old next month.";

배열(Array)

배열 타입은 두 가지 방법으로 쓸 수 있습니다. 첫 번째 방법은, 배열 요소들을 나타내는 타입 뒤 []를 쓰는 방법입니다.

let list: number[] = [1,2,3];

두 번째 방법은 제네릭 배열 타입을 쓰는 방법입니다. Array<elemType>

let list: Array<number> = [1,2,3];

튜플(Tuple)

튜플 타입을 사용하면, 요소의 타입과 개수가 고정된 배열을 표현할 수 있습니다. 단 요소들의 타입이 모두 같을 필요는 없습니다. 예를 들어, number, string이 쌍으로 있는 값을 나타내고 싶을 수 있습니다.

// 튜플 타입으로 선언
let x = [string, number];
// 초기화
x = ["hello", 10]; // 성공
// 잘못된 초기화
x = [10, "hello"]; // 오류

정해진 인덱스에 위치한 요소에 접근하면 해당 타입이 나타납니다.

console.log(x[0].substring(1)); // 성공
console.log(x[1].substring(1)); // 오류, 'number'에는 'substring'이 없습니다.

정해진 인덱스 외에 다른 인덱스에 있는 요소에 접근하면, 오류가 발생하며 실패합니다.

x[3] = "world"; // 오류, '[string,number]'에는 프로퍼티 '3'이 없습니다.

console.log(x[5].toString()); // '[string, number]' 타입에는 프로퍼티 '5'가 없습니다.

이 외에도 다른 기본 타입들이 있습니다. (링크)

함수에서 타입 정의하기

간단한 덧셈 함수를 작성하겠습니다

function sum (x: number, y: number):number {
  return x + y;
}

sum(1, 2);

위처럼 인자에 타입들과 함수의 결과물의 타입을 정할 수 있습니다.

function sum (x: number, y: number):number {
  return null;
}

반환 값으로 null을 줄 경우, 'null'형식은 'number'형식에 할당할 수 없습니다. ts(2322) 라고 에디터에서 에러를 알려줍니다.

만약 함수에서 아무것도 반환하지 않아야 한다면 반환 타입을 void로 설정하면 됩니다.

function returnNothing(): void{
  console.log('나는 아무것도 반환하지 않아!');
}

interface 사용하기

interface는 클래스 또는 객체를 위한 타입을 지정 할 때 사용되는 문법입니다.

function printLabel(labeledObj: {label: string}) {
  console.log(labeledObj.label);
}

let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

타입 검사는 printLabel을 호출합니다. printLabel함수는 string타입 label을 갖는 객체를 하나의 매개변수로 가집니다. 이 객체는 실제로는 size도 가지고 있지만, 컴파일러는 최소한으로 필요한 프로퍼티가 있는지와 타입이 잘 맞는지만 검사합니다.

이번에는 같은 예제를, 문자열 타입의 프로퍼티 label을 가진 인터페이스로 다시 작성해 보겠습니다.

interface LabeledValue {
  label: string;
}

function printLabel(labeledObj: LabeledValue) {
  console.log(labeledObj.label);
}

let myObj = {size: 10, label: "size 10 Object"};
printLabel(myObj);

이 인터페이스는 여전히 string타입의 label 프로퍼티 하나를 가진다는 것을 의미합니다. 다른 언어처럼 printLabel에 전달한 객체가 이 인터페이스를 구현해야 한다고 명시적으로 애기할 필요는 없습니다. 여기서 중요한 것은 형태뿐입니다. 함수에 전달된 객체가 나열된 요구 조건을 충족하면 됩니다.

타입 검사는 프로퍼티들의 순서를 요구하지 않습니다. 단지 인터페이스가 요구하는 프로퍼티들이 존재하는지와 프로퍼티들이 요구하는 타입을 가졌는지만을 확인합니다.

선택적 프로퍼티(Optional Properties)

다만, 인터페이스가 모든 프로퍼티가 필요한 것은 아닙니다. 어떤 조건에서만 존재하거나 아예 없을 수도 있습니다.

interface LabeledValue{
  label: string;
  size?: number;
}

function printLabel(labeledObj: LabeledValue) {
  console.log(labeledObj.label);
}

let myObj = {size: 10, label: "size 10 Object"};
printLabel(myObj);

선택적 프로퍼티 이름 끝에 ?를 붙여 표시합니다.

선택적 프로퍼티의 이점은 인터페이스에 속하지 않는 프로퍼티의 사용을 방지하면서, 사용 가능한 속성을 기술하는 것입니다. 예를 들어, LabeledValue안의 size 프로퍼티 이름을 잘못 입력하면, 오류 메시지로 알려줍니다.

interface LabeledValue{
  label: string;
  size?: number;
}

function printLabel(labeledObj: LabeledValue) {
  console.log(labeledObj.label);
  // 오류, 'LabeledValue'에 'sizz'프로퍼티는 존재하지 않습니다.
  console.log(labeledObj.sizz);
}

let myObj = {size: 10, label: "size 10 Object"};
printLabel(myObj);

interface에 대한 더 자세한 내용 확인하기 (링크)

Type Aliases 사용하기

타입 별칭은 타입의 새로운 이름을 만듭니다. 타입 별칭은 때때로 인터페이스와 유사합니다만, 원시 값, 유니언, 튜플 그리고 직접 작성해야 하는 다른 타입의 이름을 지을 수 있습니다.

type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
  if(typeof n === "string") { // 문자열인지 함수인지 판별
	return n;
  }
  else {
    return n();
  }
}

별칭은 새로운 타입을 만드는 것이 아닙니다. 그 타입을 나타내는 새로운 이름 을 만드는 것입니다.
interfacetype 둘 중 아무거나 써도 상관은 없지만 일관성 있게 사용하면 된다고 합니다. 다만 라이브러리를 작성하거나 다른 라이브러리를 위한 타입 지원 파일을 작성하게 될 때는 interface를 사용하는 것이 권장 되고 있습니다.

제네릭(Generics)

제네릭은은 함수, 클래스, interface, type을 사용하게 될 때 여러 종류의 타입에 대하여 호환을 맞춰야 하는 상황에서 사용하는 문법입니다.

먼저, 인수로 무엇이 오던 그대로 반환하는 identity 함수를 만들어봅시다.
제네릭이 없다면, identity 함수에 특정 타입을 주어야 합니다.

function identity(arg: any): any {
  return arg;
}

const message = identity("hello world!");

any를 쓰면 arg가 어떤 타입이든 받을 수 있다는 점에서 제네릭이지만, 실제로 함수가 반환할 때 어떤 타입인지에 대한 정보를 잃게 됩니다.

이런 상황에 제네릭을 사용하면 됩니다. 제네릭은 다음과 같습니다.

function identity<T>(arg:T): T {
  return arg;
}

const message = identity("hello world!");

제네릭을 사용 할 때 <T>처럼 꺽쇠 안에 타입의 이름을 넣어서 사용하며, 이렇게 설정해주면 any처럼 어떤 타입이든 들어올 수 있으면서, 사용할 때 타입이 깨지지 않게 됩니다.

interface에서 Generics 사용하기

interface Items<T>{
  list: T[];
}

const items: Items<number> = {
  list: [1,2,3,4]
};

Items<number>라는 타입을 사용하게 되면 <T>에서는 number타입이 들어가며, list에서도 number[] 타입을 지니고 있게 됩니다. 문자열로 된 리스트를 사용하고 싶을 땐, 타입의 형태를 Items<string>으로 바꾸면 됩니다.

Type Aliases에서 Generics 사용하기

type Items<T> = {
  list: T[];
};

const items: Items<number> = {
  list: [1,2,3,4]
};

interface와 유사합니다.

Generics에 대한 더 자세한 내용 확인하기 (링크)


profile
커피가 본체인 개발자 ☕️

0개의 댓글