본문 바로가기
카테고리 없음

[React][Typescript] 타입스크립트 개념 심화

by 꽁이꽁설꽁돌 2024. 8. 30.
728x90
반응형

목차

     

    구조적 서브타이핑

    //구조적 서브타이핑
    //이름이 다른 객체라도 가지고 있는 속성이 동일하다면
    //타입스크립트는 서로 호환 가능하다.
    
    
    interface Pet {
        name: string;
    }
    interface Cat{
        name: string;
        age: number;
    }
    
    let pet : Pet;
    let cat: Cat = {name: "zag", age: 2};
    
    pet = cat;
    
    //함수도 가능
    function greet(pet: Pet){
        console.log(pet.name);
    }
    greet(cat);
    
    
    //class, interface, type, 모두 구조적 서브 타이핑 가능

     

    값과 타입 공간에 동시에 존재하는 심볼인 class 와 enum

    class Rectangle {
      "height": number;
      "width": number;
      constructor(height: number, width: number) {
        this.width = width;
        this.height = height;
      }
    }
    
    
    enum MyColors {
      BLUE = "fsf",
      YELLOW = "sfs",
      RED = "sfss",
    }
    
    //값 공간에서 사용
    function whatMinColor(palette: { RED: string }) {
      return palette.RED;
    }
    
    //타입으로 사용
    type color = keyof typeof MyColors;

     

    여러 타입들

    //symbol은 어떤 값과도 중복되지 않는 유일한 값
    const MOVIE_TITLE = Symbol('title');
    const MUSIC_TITLE = Symbol('title');
    
    console.log(MOVIE_TITLE === MUSIC_TITLE); //false
    
    
    //bigint
    const bignum: bigint = BigInt(131313131313131);
    const bignum2: bigint = 131313131313131n;
    
    
    //{} 객체 리터럴 방식으로 객체를 생성할 때 사용
    const book : {title: string; born: number; }={
        title: "sfs",
        born: 1992
    }
    const book2 : {title: string; born: number; }={
        title: "sfs",
        born: 1992
        color: 'red' //error
    }
    
    //unknown
    any와 유사하지만 객체 내부에 접근하는 시도는 모두 error발생
    const ab: unknown = () => {
      console.log("hi");
    };
    ab();
    
    //never
    //에러를 던지는 경우 실행
    //무한히 함수가 실행되는 경우
    function generateError(res: Response): never{
    	throw new Error(res.getMessage());
    }
    
    //tuple
    //배열의 길이까지 정해줌 대표적인 예 useState
    let tuple: [number] = [1];
    tuple = [1, 2]; //error
    tuple = ['a', 1]; // error

     

    타입 조합

    //교차 타입 -> 타입 결합
    type item = {
        id: number;
        name: string;
    }
    type specialItem = item & {health: number};
    
    //유니온 타입
    
    type aitem = {
        id: number;
        name: string;
        personality: number;
    }
    
    type bitem = {
        id: number;
        name: string;
        effet: string;
    }
    
    type item = aitem | bitem;
    
    //타입이 둘중 하나여야 함
    const pitem : item = {
        id: 1,
        name: 'items',
        effet: 's',
    };
    
    //맵드 타입 ->반복적인 타입 선언의 효과적 줄임 가능
    type Example = {
      a: number;
      b: string;
      c: boolean;
    };
    
    type Subset<T> = {
      [K in keyof T]?: T[K];
    };
    
    const aE: Subset<Example> = { a: 3 };
    const bE: Subset<Example> = { a: 3 };
    const cE: Subset<Example> = { a: 3, c: true };

     

    제네릭

    제네릭 함수

    //제네릭 문법 <parameter Symbol(매개변수 기호)>
    //선언 방법<>내부에 임의의 기호심볼을 집어넣는다.
    //보통 매개변수 기호로 T나 U를 많이 사용한다.
    //ex) <T>, <T, U>
    
    
    function getFirstElement<T>(arr: T[]): T {
      return arr[0];
    }
    
    // 숫자 배열에서 첫 번째 요소 반환
    const firstNumber = getFirstElement([1, 2, 3]); // 타입은 number
    
    // 문자열 배열에서 첫 번째 요소 반환
    const firstString = getFirstElement(["a", "b", "c"]); // 타입은 string

     

    타입 제한걸기

    interface TypeWithLength {
      length: number;
    }
    
    //length 속성을 가진 타입만 받는다.
    function exampleFunc2<T extends TypeWithLength>(arg: T): number {
      return arg.length;
    }
    
    const arr: string[] = ['1', "2"];
    
    exampleFunc2(arr);
    
    exampleFunc2(1); //error

     

    제네릭 인터페이스

    // API 응답의 일반적인 구조를 정의하는 제네릭 인터페이스
    interface ApiResponse<T> {
      status: number;
      message: string;
      data: T;
    }
    
    // 사용자 정보를 담는 타입
    interface User {
      id: number;
      name: string;
      email: string;
    }
    
    // API 응답으로 사용자 정보를 받을 때의 타입
    const userResponse: ApiResponse<User> = {
      status: 200,
      message: "Success",
      data: {
        id: 1,
        name: "John Doe",
        email: "john@example.com"
      }
    };

     

    interface 확장

    // 기본 인터페이스
    interface Person {
      name: string;
      age: number;
    }
    
    // 확장된 인터페이스
    interface Employee extends Person {
      employeeId: number;
      department: string;
    }
    
    const employee: Employee = {
      name: "John Doe",
      age: 30,
      employeeId: 1234,
      department: "Engineering",
    };
    
    console.log(employee);

     

    타입 가드

    //복잡한 타입을 작은 범위로 축소하여 타입 안전성을 높인다.
    
    function replaceHyphen(date: string| Date): string| Date{
        if(typeof date === "string"){
            return date.replace(/-/g, "/");
        }
        return date;
    
    }
    //이렇게 만들어 줌으로써 올바르지 않은 에러 객체가 들어가면 오류가 발생하게끔 만들어 준다
    // 개별 타입 정의
    type TextError = {
      type: "text";
      message: string;
    };
    
    type ToastError = {
      type: "toast";
      message: string;
      duration: number;
    };
    
    type AlertError = {
      type: "alert";
      message: string;
      alertLevel: "info" | "warning" | "error";
    };
    
    // 유니온 타입 정의
    type ErrorType = TextError | ToastError | AlertError;
    
    // 객체 예제들
    const error1: ErrorType = {
      type: "text",
      message: "This is a text error."
    };
    
    const error2: ErrorType = {
      type: "toast",
      message: "This is a toast error.",
      duration: 3000 // 밀리초 단위로 지속 시간 설정
    };
    
    const error3: ErrorType = {
      type: "alert",
      message: "This is an alert error.",
      alertLevel: "error" // 알림 수준 설정
    };

     

     

    타입 표명(Type Assertion)

    TypeScript에서는 시스템이 추론 및 분석한 타입 내용을 우리가 원하는 대로 얼마든지 바꿀 수 있다. 이때 "타입 표명(type assertion)"이라 불리는 메커니즘이 사용됩니다. TypeScript의 타입 표명은 프로그래머가 컴파일러에게 내가 너보다 타입에 더 잘 알고 있고, 나의 주장에 대해 의심하지 말라고 하는 것과 같다.

     const data = useActionData() as { errors: string[]; message: string };
     
     //이렇게 react-router-dom에서 강제로 타입 지정을 해주면 오류가 나지 않는다.
     //action이나 loader에서 데이터 불러올 때 잘 사용된다.

     

    useRef의 타입

    interface MutableRefObject<T> {
      current: T;
    }
    
    interface RefObject<T> {
      readonly current: T | null;
    }
    
    
    import { useEffect, useRef } from 'react'
    
    const App = () => {
      const value = useRef<number>(0)  // MutableRefObject<number>
      
      useEffect(() => {
        value.current += 1
      }, [])
    }
    
    import { useEffect, useRef } from 'react'
    
    const App = () => {
      const value = useRef<number>(null)  // RefObject<number>
      
      useEffect(() => {
        value.current += 1  // 에러!
      }, [])
    }
    
    // readonly로 선언된 current가 객체라는 점에 있다. 
    //readonly는 shallow하게 동작하기 때문에 current의 하위 프로퍼티 value는 수정이 가능하다.
    
    import { useEffect, useRef } from 'react'
    
    const App = () => {
      const inputRef = useRef<HTMLInputElement>(null)  // RefObject<HTMLInputElement>
      
      useEffect(() => {
        inputRef.current?.value = "no error"
      }, [])
    }

     

    차후 추가 예정...

    반응형