[TIL] 내일배움캠프 React 과정 2023.01.17_Typescript

Today I Learnend

  • Typescript 기초 강의 수강

Type Alias (사용자 정의 타입)

// type.ts
type Hero = {
    name: string;
    power: number;
    height: number;
};
import type { Hero } from './type';

const hero1: Hero = {
  name: '슈퍼맨',
  power: 1000,
  height: 190,
};

// 동일함
const printHero = (hero: { name: string; power: number; height: number }) => {
const printHero = (hero: Hero) => {
  console.log(hero.name, hero.power);
};

console.log(printHero(hero1));

 

interface & Intersection Type

interface란?

  • 인터페이스는 일반적으로 타입 체크를 위해 사용되며 변수, 함수, 클래스에 사용할 수 있다. 즉 인터페이스는 변수나 함수, 그리고 클래스가 만족해야 하는 최소 규격을 지정할 수 있게 해주는 도구이다.

 

기본 정의

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

const person1: Person = { name: 'js', age: 20 };
const person2: Person = { name: 'ljs', age: 'twenty' }; // Error

 

선택 속성

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

const person1: Person = { name: 'js' };

 

Read only 속성

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

const person1: Person = { name: 'js' };
person1.name = 'ljs'; // Error

let readOnlyArr: ReadonlyArray<number> = [1,2,3];
readOnlyArr.splice(0,1); // error
readOnlyArr.push(4); // error
readOnlyArr[0] = 100; // error

 

index type

interface Person {
  readonly name: string;
  [key: string]: string | number;
}

const p1: Person = { name: 'js', birthday: '비밀', age: 20 };

 

함수 타입

interface Print {
  (name: string, age: number): string;
}
// type Print = (name: string, age: number) => string;

const getNameAndAge: Print = function (name, age) {
  return `name: ${name}, age: ${age}`;
};

 

인터페이스 확장

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

interface Korean extends Person {
  birth: 'KOR';
}

interface Korean {
  name: string;
  age: number;
  birth: 'KOR';
}

interface Developer {
  job: 'developer';
}

interface KorAndDev extends Korean, Developer {}

interface KorAndDev {
  name: string;
  age: number;
  birth: 'KOR';
  job: 'developer';
}

 

intersection Type

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

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

type DevJob = Person & Developer;

const nbcPerson: DevJob = {
  name: 'a',
  age: 20,
  skill: 'ts',
};

여러 타입을 모두 만족하는 하나의 타입

 

type vs interface

  • 타입 별칭과 인터페이스의 가장 큰 차이점은 타입의 확장 가능 / 불가능 여부이다.
  • 인터페이스는 확장이 가능한데 반해 타입 별칭은 확장이 불가능하다.
  • 따라서, 가능한한 type 보다는 interface로 선언해서 사용하는 것을 추천한다.

제네릭은 보통 여러 타입을 넣을 수 있는 공통 함수에 많이 쓰이는데 프로젝트 전반에 공통 함수를 사용하는 일은 많이 없기 때문에 제네릭 많이 사용하지 않음

 

 

제네릭(Generics)

  • 제네릭이란 타입을 마치 함수의 파라미터처럼 사용하는 것
function getText(text: any): any {
  return text;
}

getText('hi'); // 'hi'
getText(10); // 10
getText(true); // true
function getItemArray(arr: any[], index: number): any {
  return arr[index];
}

function pushItemArray(arr: any[], item: any): void {
  arr.push(item);
}

const techStack = ['js', 'react'];
const nums = [1, 2, 3, 4];

getItemArray(techStack, 0); // 'js'
pushItemArray(techStack, 'ts'); // ['js', 'react', 'ts']

getItemArray(nums, 0); // 1
pushItemArray(nums, 5); // [1, 2, 3, 4, 5];

👇

function getItemArray<T>(arr: T[], index: number): T {
  return arr[index];
}

function pushItemArray<T>(arr: T[], item: T): void {
  arr.push(item);
}

const techStack = ['js', 'react'];
const nums = [1, 2, 3, 4];

getItemArray(techStack, 0); // 'js'
pushItemArray<string>(techStack, 'ts'); // ['js', 'react', 'ts']
// pushItemArray<number>(techStack, 123); // Error

 

제네릭 타입 변수

function printOut<T>(input: T): T {
  console.log(input.length); // Error: T doesn't have .length
  return input;
}

function printOut<T>(input: T[]): T[] {
  console.log(input.length);
  return input;
}

 

제네릭 제약 조건

interface LengthWise {
  length: number;
}

function printOut<T extends LengthWise>(input: T): T {
  console.log(input.length);
  return input;
}

// printOut(10); // Error, 숫자 타입에는 `length`가 존재하지 않으므로 오류 발생
// printOut({ length: 0, value: 'hi' }); // `input.length` 코드는 객체의 속성 접근과 같이 동작하므로 오류 없음

 

타입 추론

let a = 123;
let b = 'abc';

a = 'abc'; // Error
b = 123; // Error

const arr = [1, 2, 3];
const [n1, n2, n3] = arr; // n1 type: number
arr.push('a'); // Error

const obj = { numId: 1, stringId: '1' };
const { numId, stringId } = obj;
console.log(numId === stringId); // Error(number !== string)
const func1 = (a = 'a', b = 1) => {
  return `${a} ${b};`;
};
func1(3, 6); // Error

const v1: number = func1('a', 1); // Error-v1은 string

const func2 = (value: number) => {
  if (value < 10) {
    return value;
  } else {
    return `${value} is big`;
  }
};

 


Programmers 문제 풀기

최댓값 만들기

function solution(numbers) {
    let answer = 0;
    for (const num of numbers) {
        for (const num2 of numbers) {
            if ( num !== num2 && num * num2 >= answer) {
                answer = num * num2
            }
        }
    }
    return answer
}

처음에 이렇게 풀었는데 배열이 [1, 1, 2, 3, 4, 5, 5]인 경우에 if 조건문 때문에 25가 출력되지 않고 20이 출력된다.

 

function solution(numbers) {
    let answer = 0;
    for (const i in numbers) {
        for (const i2 in numbers) {
            if ( i !== i2 && numbers[i] * numbers[i2] >= answer) {
                answer = numbers[i] * numbers[i2]
            }
        }
    }
    return answer
}

그래서 for...of문->for...in문으로 수정하고 if문의 조건을 i !== i2일 때로 수정했다. 어떻게 풀긴 풀었는데 코드가 너무 지저분하고 이중 for문을 사용하지 않는 방법은 없을지 궁금했다.

 

다른 사람의 풀이

function solution(numbers) {
    numbers.sort((a,b)=>b-a);
    return numbers[0]*numbers[1];
}

나는 코드 진짜 더럽게 짰는데 다른 사람 풀이에 깔끔한 코드 있으면 기분이....너무 씁쓸하다😢 sort 메서드를 이용해서 배열을 내림차순으로 정렬하고 배열의 최댓값인 [0]번과 [1]번을 곱한다! sort 메서드는 원본 배열을 직접 변경하여 정렬된 배열을 반환하기 때문에 바로 numbers 배열의 인덱스로 접근할 수 있는 것이다.

 

sort() 메서드

숫자 배열 오름차순 정렬

const scores = [2, 3, 10, 1, 100];
scores.sort((a, b) => a - b);
console.log(scores); // [1, 2, 3, 10, 100]

 

숫자 배열 내림차순 정렬

const scores = [2, 3, 10, 1, 100];
scores.sort((a, b) => b - a);
console.log(scores); // [100, 10, 3, 2, 1]

참고 https://velog.io/@yunsungyang-omc/JS-배열-정렬-메소드-sort

 

 

문자 반복 출력하기

function solution(my_string, n) {
    return my_string.split('').map((str) => str.repeat(n)).join('')
}

사실 이 문제 오늘 하루종일 고민했다. 문자 반복하는 것을 for문 돌리고 배열 push를 n번 반복할 수 있나? 하는 방향으로만 접근해서 답을 찾지 못했었는데 갑자기 문자열을 반복해 주는 메서드가 있을까 궁금해져서 검색해 보니 있었다. 그래서 repeat 메서드를 알고 나서는 금방 풀 수 있었다.

 

  • repeat() 메서드는 문자열을 주어진 횟수만큼 반복해 붙인 새로운 문자열을 반환한다.
  • str.repeat(count

my_string이라는 문자열을 split()을 이용해서 문자열 하나하나 쪼갠 후 배열에 넣고, 이 배열에 map을 돌려서 각 문자열을 세 개씩 넣어주면 "h"->"hhh"가 된다. 그리고 이 배열을 join 메서드를 이용해서 전부 합쳐 하나의 문자열로 만들면 끝! 오랜만에 마음에 드는 풀이였다 ㅎㅎ

map 안에 repeat까지만 돌리면 배열이 이렇게 나온다.

 


회고

최종 프로젝트를 앞두고 노트북을 새로 구매했다. 사실 지금까지 5년 사용한 낡은 그램으로 코딩한 게 기적(?)이라고 할 수 있다. 앞으로는 내 능력치를 최대한으로 발휘해 보고 싶다! 그리고 내 노트북이 느리면 나만 불편한 게 아니고 팀원들에게도 피해가 갈 수 있다는 걸 느꼈다. 그래서 이왕 사는 거 성능 제일 좋은 걸로 샀다 ㅎㅎ

 

정말 소규모의 개인 프로젝트를 진행하며 타입스크립트를 공부할까 생각 중이다. 일단 생각한 건 내가 책을 좋아하니까 도서 API를 이용하고 싶어서 인터파크 도서 API 이용해서 문학 위주로 베스트셀러 보여주고, 카카오 API 이용해서 도서 검색 기능까지? 근데 뭔가 뻔한 느낌이라 더 새롭고 재밌는 건 없을까 고민해 봐야겠다.