프로그래머스 풀스택 44

  • programmers

posted on 29 Oct 2024 under category programmers in series programmers

프로그래머스 풀스택 44

프론트엔드 기초: React + TypeScript(7)

🌊 객체 리터럴

💫 객체 리터럴

리터럴 타입 (enum보다 간단)

  • 리터럴 값은 특정 값을 나타내는 타입.

  • 해당 값이 완전히 일치해야 함.
  • 타입스크립트에는 다양한 리터럴이 존재.
    문자열 리터럴, 숫자 리터럴, 불리언 리터럴, 객체 리터럴, 타입 리터럴.. 등등


  • 문자열 리터럴 타입
    let gender : 'male' | 'female';이런 식으로 하면
    male과 female 값 둘 중 하나만 들어올 수 있게 제한 가능
    기존의 gender? : string;을 하면 다른 값이 들어올 수 있었음

  • 숫자 리터럴 타입
    let speed : 50|100|200;
    speed=100; : 유효
    speed=150; : 에러. 150은 허용 X

  • 불리언 리터럴 타입
    let isTrue : true;
    isTrue = true; : 유효
    isTrue = false; : 에러. false 허용 X

  • 객체 리터럴 타입(가장 많이 사용)
    let person : { name: 'John', age: 30 };
    person : { name: 'John', age: 30 }; : 유효
    person : { name: 'Alice', age: 25 }; : 에러. 값이 일치해야 함.

  • 타입 별칭
    type CardinalDirection = 'North'|'East'|'South'|'West';
    let direction : CardinalDirection;
    direction = 'North'; : 유효
    direction = 'Northeast'; : 에러. ‘Northeast’ 허용 X

리터럴 타입 사용 시 장점

  • 코드의 가독성 UP
  • 잘못된 값이 들어오는 것 방지

🌊 유니온, 타입별칭, 타입가드

let anyVal : any = 100;
anyVal = true;

any 타입

  • any는 아무 값을 받을 수 있음
  • 하지만 타입스크립트는 타입에 관한 정보가 많을수록
    개발자의 의도를 명확하게 전달하기 좋기때문에 (효과적인 유지보수 가능)
    any는 지양해야 함
  • any가 필요한 경우 : 타입을 지정할 수 없는 제한적인 경우(ex. 서드파티에서 데이터를 가져올 때)


💫 유니온

유니온 타입

  • 공용체(유니온)
  • 제한된 타입을 동시에 지정하고 싶을 때가 있음
  • let anyVal : number | string;
  • | 기호를 사이에 두고 동시에 타입을 지정 가능
  • anyVal 변수는 number나 string 타입 중 아무 타입의 값이 올 수 있음
let numStr : number | string = '100';
function convertToString(val : number | string):string {
    return String(val); //무조건 문자열 변환 출력
}
function convertToNumber(val : number | string):number {
    return Number(val); // 무조건 숫자 변환 출력
}
console.log(convertToString(numStr));
console.log(convertToNumber(numStr));
  • 콘솔을 찍으면 문자열 100과 숫자 100이 출력됨
  • numStr의 값을 숫자 100으로 해도 마찬가지




💫 타입 별칭(Type Alias)

  • 타입(클래스, 공용체, 열거형..등등)을 새롭게 재정의
  • 기존에 있던 걸 결합해서 재정의함
    type strOrNum = number | string;
type strOrNum = number | string;
let numStr : strOrNum = '100';
function convertToString(val : strOrNum):string {
    return String(val); //무조건 문자열 변환 출력
}
function convertToNumber(val : strOrNum):number {
    return Number(val); // 무조건 숫자 변환 출력
}
  • 타입 별칭을 사용하면 가독성이 좋아짐!


💫 타입가드

type strOrNum = number | string;
let numStr : strOrNum = '100';
let item : number;
function convertToString(val : strOrNum):string {
    item = numStr; // 
    return String(val); //무조건 문자열 변환 출력
}
  • 여기서 item = numStr;은 item 변수에 대입되는 numStr의 타입이 유니온타입이라 오류가 발생함(string이 들어갈 수도 있으니까)
  • 그래서 typeof 연산자를 사용시 해결가능

타입가드 적용

type strOrNum = number | string;
let numStr : strOrNum = '100';
let item : number;
function convertToString(val : strOrNum):string {
    if(typeof val ==='string') {
        item = 0;
    }else{
        item = val;
    }
    return String(val); //무조건 문자열 변환 출력
}
  • 이렇게 유니온 타입을 typeof 연산자를 통해 타입검증을 하는 걸 타입가드라고 함


요약

  • any 타입 : 타입 체크 X, 어떤 타입이 와도 OK
  • 유니온 타입 : 제한된 타입들을 파이프라인으로 구분하여 동시에 지정
  • 타입 앨리어스 : 반복되는 코드를 재사용(타입 재정의)
  • 타입 가드 : typeof 연산자를 이용하여 타입 검증 수행

🌊 Array와 Tuple

💫 Array와 Tuple

Array와 Tuple의 차이점

  • Array는 길이가 가변적, 동일한 타입의 요소로 구성
  • Tuple은 길이가 고정적, 각 요소의 타입이 정해짐


let numbers : number[] = ([1, 2, 3, 4, 5]);
let fruits : string[] = ['apple', 'banana', 'orange'];
for(let i = 0; i < numbers.length; i++) {
    console.log(numbers[i]);
}
for(let i = 0; i < fruits.length; i++) {
    console.log(fruits[i]);
}
  • 기본 숫자, 문자열 배열

let mixedArray : (number | string)[] = [1, 'two', 3, 'four'];
for(let i = 0; i < mixedArray.length; i++) {
    console.log(mixedArray[i]);
};
  • 배열의 유니온 타입

let infer = [1, 2, 3]; 
for(let i = 0; i < infer.length; i++) {
    console.log(infer[i]);
};
  • 타입 추론 기능

let readOnlyArray : ReadonlyArray<number> = [1, 2, 3];
  • 수정이 안되는 읽기전용 Array

let greeting : [number, string, boolean] = [1, 'hello', true];
for(let i = 0; i < greeting.length; i++) {
    console.log(greeting[i]);
};
  • 튜플 : 배열의 형태지만 타입의 순서가 정해져 있음.

let firstArray = [1, 2, 3];
let secondArray = [4, 5, 6];
let combineArray = [...firstArray, ...secondArray]; //Spread 연산자(...) => 무장해제
for(let i = 0; i < combineArray.length; i++) {
    console.log(combineArray[i]);
};
  • Spread 연산자(Array 관련)

🌊 클래스와 객체 만들기

💫 클래스와 객체 만들기

타입스크립트 기반의 객체 지향 프로그래밍(Object-Oriented Programming, OOP)

  • 구조체, 공용체, 열거형, 인터페이스, 클래스…
  • 연관된 변수와 함수들을 한 덩어리로 묶음
  • 클래스와 객체
  • 클래스(설계도, 생상틀)는 객체의 뼈대, 객체는 클래스의 실체
    붕어빵틀(뼈대), 붕어빵(실체)

멤버변수 == 속성 == 프로퍼티
멤버함수 == 메소드

// 클래스 생성
class Employee {
    empName : string;
    age : number;
    empJob : string;
    printEmp = () : void => {
        console.log(this.empName + '의 나이는 ' + this.age +'이고, 직업은 ' + this.empJob + '입니다.');
    }
}
// 객체 생성
let employee1 = new Employee();
// 초기값 지정
employee1.empName ='kim';
employee1.age = 25;
employee1.empJob = '개발자';
// 메소드 호출
employee1.printEmp();
  • 클래스 생성 후 객체를 생성하면
    그 객체는 클래스 안에 선언된 프로퍼티, 메소드를 객체 자신의 프로퍼티와 메소드로 갖게 됨

🌊 생성자

💫 생성자

객체 지향 프로그래밍에는 생성자가 내장됨
프로퍼티의 초기값을 생성자를 이용해 설정할 수 있음
모든 클래스는 생성자라는 메소드를 가질 수 있음
컴파일 기반의 언어에서는 생성자를 따로 만들어야 함

생성자 메소드 규칙
클래스와 같은 이름을 갖고 있으면 됨

하지만 타입스크립트는 constructor() 이런식으로 생성자가 고정되어 사용함

// 클래스 생성
class Employee {
    empName : string;
    age : number;
    empJob : string;
    constructor(empName : string, age : number, empJob : string) {
        this.empName = empName; // 자기 자신의 객체
        this.age = age;
        this.empJob = empJob;
    }
    printEmp = () : void => {
        console.log(this.empName + '의 나이는 ' + this.age +'이고, 직업은 ' + this.empJob + '입니다.');
    }
}
// 객체 생성
let employee1 = new Employee('kim', 30, '소프트웨어개발자');
// 메소드 호출
employee1.printEmp();
  • 필수 매개변수는 선택적 매개변수(?사용) 앞에 와있어야 함
    constructor(empName : string, age? : number, empJob? : string)

🌊 접근지정자

💫 접근지정자

프로퍼티를 생성자를 이용해 객체를 초기화했음
프로퍼티의 값은 객체를 통해서 다른 값으로 변경할 수 있음

접근을 제한 👉 객체 지향의 “캡슐화”

  • public, private, protected 을 사용해 접근을 통제할 수 있음

  • public : default로 설정

  • private : 완전히 나만 접근 가능
    private를 사용하면 클래스 밖에서는 접근 불가능
      class Employee {
          private _empName : string; // private를 사용하면 클래스 밖에서는 접근 불가능
          private _age : number;
          private _empJob : string;
          // ...생략
      }
    

    이를 해결하기 위해 getter와 setter를 사용함!
    private 변수를 쓸경우 변수명 앞에 _을 붙여줌. 👉 _변수명

  • protected : 상속 관계(부모-자식)에만 접근 가능

🌊 getter와 setter

💫 getter와 setter

타입스크립트 말고도 일반적으로 함수에서 어떤 데이터를 다루는 함수는 get/set함수라고 얘기를 함
클래스 내의 메소드에서 사용을 하게 됨
get/set 함수의 존재 이유 : 데이터들을 직접 접근하지 않고 ,특정 메소드를 통해서 출입을 해야하므로
인터페이스를 만들어줄 때 데이터를 다루는 메소드같은 경우 get/set를 한 쌍으로 만들어주는 게 관례 같은 것
👉 이걸 타입스크립트에서는 getter와 setter로 사용하는 것일 뿐임

    get empName(){
        return this._empName;
    }

    set empName(val : string){
        this._empName = val;
    }
// 클래스 생성
class Employee {
    constructor(
        private _empName : string,
        private _age : number,
        private _empJob : string
        ){
    }
    // get/set
    get empName(){
        return this._empName;
    }
    set empName(val : string){
        this._empName = val;
    }
    printEmp = () : void => {
        console.log(this._empName + '의 나이는 ' + this._age +'이고, 직업은 ' + this._empJob + '입니다.');
    }
}
// 객체 생성
let employee1 = new Employee('kim', 30, '소프트웨어개발자');
employee1.empName = 'lee'; // 접근지정자 적용이 필요함 -> get/set 설정
// 메소드 호출
employee1.printEmp();
  • 클래스 생성 부분 코드 고도화
  • 프로퍼티에 대한 선언부, 생성자에서 초기화하는 부분, 넘겨주는 부분이 3번 중복되는 걸 해결 완료

🌊 느낀 점(YWT)

Y 일을 통해 명확히 알게 되었거나 이해한 부분(한 일)에 대해 정리 :
객체 리터럴, 유니온, 타입 별칭, 생성자/접근지정자, 등등

W 배운 점과 시사점 :

  • 객체 리터럴 타입(가장 많이 사용)
    let person : { name: 'John', age: 30 };
    person : { name: 'John', age: 30 }; : 유효
    person : { name: 'Alice', age: 25 }; : 에러. 값이 일치해야 함.

  • any 타입 : 타입 체크 X, 어떤 타입이 와도 OK
  • 유니온 타입 : 제한된 타입들을 파이프라인으로 구분하여 동시에 지정
  • 타입 앨리어스 : 반복되는 코드를 재사용(타입 재정의)
  • 타입 가드 : typeof 연산자를 이용하여 타입 검증 수행

T 응용하여 배운 것을 어디에 어떻게 적용할지:
클래스와 객체를 생성하고 코드를 고도화할 수 있게 됨