타입스크립트 개념 정리

:D ·2023년 2월 13일
0
post-thumbnail

캡틴판교님의 타입스크립트 입문 - 기초부터 실전까지를 듣고 정리해보았다.

변수 타입

타입스크립트의 기본 타입에는 크게 12가지가 있다.
Boolean, Number, String, Object, Array ,Tuple, Enum, Any, Void, Null, Undefined, Never

// 문자열
const str: string = 'hi';

// 숫자
const num: number = 10;

// 배열
const arr: number[] = [1,2,3];

//튜플
const address: [string, number] = ['gangnam', 100];

// 객체
const obj: object = {};

// 진위값
const show: boolean = true;

// any => 모든 타입에 대해서 허용
const str: any = 'hi';

// void => 반환 값이 없다
function log(a: string): void {
  	console.log(a);
}

함수 타입

// 함수의 파라미터와 반환 값에 타입을 정의 
function sum(a: number, b: number): number {
	return a + b;
}

타입스크립트에서 함수의 매개변수는 정의된 매개변수 값만 받을 수 있다.

function sum(a: number, b: number): number {
	return a + b;
}
sum(10); // error, too few parameters
sum(10,20,30); // error, too many parameters

매개변수의 갯수만큼 인자를 넘기지 않도록 하고싶다면 ?을 이용해서 아래와 같이 정의하면 된다.

// 함수의 옵셔널 파라미터
function log(a: string, b?: string, c?: string) {}
log('hello world'); 
sum('hello','ts'); 

인터페이스

// 변수에 인터페이스 활용
interface User {
  age: number;
  name: string;
}

var seho: User = {
  age: 33,
  name: '세호'
}
// 함수에 인터페이스 활용
function getUser(user: User) {
  console.log(user);
}

var capt: User = {
  age: 100,
  name: '캡틴'
}

getUser(capt);
// 함수의 스펙에 인터페이스 활용

interface SumFunction {
  (a: number, b: number): number;
}

var sum: SumFunction;
sum = function(a: number, b: number): number {
  	return a + b;
}
// 인덱싱
interface StringArray {
  [index: number]: string
}

var arr: StringArray = ['a','b','c'];
// 딕셔너리 패턴
interface StringRegexDictionary {
  [key: string]: RegExp
}

var obj: StringRegexDictionary = {
  sth: /abc/,
  cssFile: /\.css$/,
  jsFile: /\.js$/
}
// 인터페이스 확장
interface Person {
  age: number;
  name: string;
}

interface Developer extends Person {
 language: string; 
}

타입 별칭

// string 타입을 사용할 때
const name: string: 'capt';

// 타입 별칭을 사용할 때
type MyName = string;
const name: MyName = 'capt';

간단한 타입 뿐만아니라 interface 레벨의 복잡한 타입에도 별칭을 부여할 수 있다.

type Developer = {
  name: string;
  skill: string; 
}

타입 별칭 vs 인터페이스

타입 별칭은 새로운 타입 값을 하나 생성하는 것이 아니라 정의한 타입에 대해 나중에 쉽게 참고할 수 있게 이름을 부여하는 것과 같다.
타입 별칭과 인터페이스의 가장 큰 차이점은 인터페이스는 확장이 가능하지만 타입은 확장이 불가능하다는 것이다.

🔥 좋은 소프트웨어는 언제나 확장이 용이해야 한다는 원칙에 따라 가급적 확장이 가능한 인터페이스로 선언하면 좋다 🔥

연산자를 이용한 타입 정의

Union Type

function logMessage(value: string | number) {
  console.log(value);
}

logMessage('hello');
logMessage(100);

유니온 타입을 사용했을 때의 장점은 타입 가드를 할 수 있다는 것이다.

// any를 사용하는 경우
function getAge(age: any) {
  age.toFixed(); // 에러 발생, age의 타입이 any로 추론되기 때문에 숫자 관련된 API를 작성할 때 코드가 자동 완성되지 않는다.
  return age;
}

// 유니온 타입을 사용하는 경우
function getAge(age: number | string) {
  if (typeof age === 'number') {
    age.toFixed(); // 정상 동작, age의 타입이 `number`로 추론되기 때문에 숫자 관련된 API를 쉽게 자동완성 할 수 있다.
    return age;
  }
  if (typeof age === 'string') {
    return age;
  }
  return new TypeError('age must be number or string');
}
interface Developer = {
  name: string;
  skill: string; 
}

interface Person = {
  name: string;
  age: number; 
}

function askSomeone(someone: Developer | Person) {
  someone.name; // 유니온 타입을 이용했을 때 공통된 속성까지만 접근할 수 있다. 
  // 나머지는 타입 가드를 이용해서 접근 가능하다.
}

Intersection Type

function askSomeone(someone: Developer & Person) {
  // someone은 Developer의 속성과 Person의 속성을 모두 갖는 타입이므로 모두 접근 가능하다. 
  someone.name;
  someone.skill;
  someone.age;
}

이넘

이넘은 특정 값들의 집합을 의미하는 자료형이다.
숫자형 이넘은 초기 값 부터 차례로 1씩 증가한다. 초기값을 정해주지 않으면 0부터 차례로 1씩 증가한다.

// 숫자형 이넘
enum Shoes {
  Nike,
  Adidas
}

var myShoes = Shoes.Nike;
console.log(myShoes); // 0
// 문자형 이넘
enum Shoes {
  Nike = '나이키',
  Adidas = '아디다스'
}

var myShoes = Shoes.Nike;
console.log(myShoes); // '나이키'

이넘 활용 사례

드롭다운처럼 목록이 필요한 경우에 이넘을 사용하면 더 정확한 코드를 작성할 수 있고, 예외처리 케이스들이 줄어들 것이다.

enum Answer {
  Yes = 'Y',
  No = 'N'
}

function askQuestion(answer: Answer) {
  if (answer === Answer.Yes) {
    console.log('정답입니다');
  }
  if (answer === Answer.No) {
    console.log('오답입니다');
  }
}

askQuestion(Answer.Yes);

클래스

타입스크립트로 클래스를 선언하면 특정 속성의 접근과 할당에 대해 제어할 수 있다.

class Person {
  private name: string;
  public age: string;
  readonly log: string;
  
  constructor (name:string, age:string) {
    this.name = name;
    this.age = age;
  }
}

제네릭

재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징이자 문법이다. 특히, 한가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트를 생성하는데 사용된다.

function logText<T>(text: T): T {
  return text;
}

logText<number>(10);
logText<string>('hello');

😎 제네릭을 사용했을 때의 이점
any를 사용하게 된다면 함수에 인자로 어떤 타입이 들어갔고 어떤 값이 반환되는지는 알 수가 없는데 T 라는 타입을 추가하면 함수를 호출할 때 넘긴 타입에 대해 타입스크립트가 추정할 수 있게된다.
또한 타입이 다른 인터페이스를 여러개 작성할 필요없이 하나의 인터페이스로 여러가지의 타입을 커버할 수 있다.

// 인터페이스에 제네릭을 선언하는 방법
interface Dropdown<T> {
  value: T;
  selected: boolean;
}
// 제네릭 타입 제한 1
function logTextLength<T>(text: T[]): T[] {
  console.log(text.length);
}

logTextLength<string>(['hi','abc']);

// 제네릭 타입 제한 2
interface LengthType {
  length: number;
}

function logTextLength<T extends LengthType>(text: T): T{
  console.log(text.length);
}

logTextLength('a');

// 제네릭 타입 제한 3
interface ShoppingItem {
  name: string;
  price: number;
  stock: number;
}

function getShoppingItemOption<T extends keyof ShoppingItem>(itemOptions: T): T {
  return itemOptions;
}

// 키 값들만 들어갈 수 있다.
getShoppingItemOption('name');

타입 추론

x에 대한 타입을 따로 지정하지 않더라도 일단 x는 number로 간주된다. 이렇게 변수를 선언하거나 초기화 할 때 타입이 추론된다.

let x = 3;

타입은 보통 몇 개의 표현식(코드)을 바탕으로 타입을 추론한다. 그리고 그 표현식을 이용하여 가장 근접한 타입을 추론하게 되는데 이 가장 근접한 타입을 Best Common Type이라고 한다.

// Best Common Type - var arr: (number | boolean) []
var arr = [1, 2, true];

타입 단언

타입스크립트 보다 개발자가 타입을 더 잘 알고 있다하면 개발자가 정한 타입으로 간주하는 것이다. 특히, DOM API 조작의 경우.

var a ='a';
var b = a as string;

타입 가드

interface Person {
  name: string;
  age: number;
}

interface Developer {
  name: string;
  skill: string;
}

// 타입 가드 정의
function isDeveloper(target: Developer | Person): target is Developer {
  retrun (target as Developer).skill !== undefined;
}

타입 호환

타입 호환이란 타입스크립트 코드에서 특정 타입이 다른 타입에 잘 맞는지를 의미한다.

구조적 타이핑이란?

구조적 타이핑(structural typing)이란 코드 구조 관점에서 타입이 서로 호환되는지의 여부를 판단하는 것이다.

interface Person {
  name: string;
}

interface Developer {
  name: string;
  skill: string;
}

var developer = Developer;
var person: Person;

person = developer;

위 코드에서 developerperson 타입에 호환이 될 수 있는 이유는 developername 속성을 가지고 있기 때문에 developerPerson 타입에 호환될 수 있다.

타입 모듈

타입스크립트에서 가리키는 모듈이라는 개념은 ES6+의 Modules 개념과 유사하고, 모듈은 전역 변수와 구분되는 자체 유효 범위를 가지며 export, import와 같은 키워드를 사용하지 않으면 다른 파일에서 접근할 수 없다.

profile
강지영입니...🐿️

0개의 댓글