☁️ goormTIL | TypeScript #55

매루·2025년 11월 26일

goormTIL

목록 보기
53/67
post-thumbnail

📅 2025-11-26

➡️ TypeSrcipt 타입 추론, interface, 타입 별칭에 대해 새롭게 알게 된 것 또는 헷갈리는 부분 정리


🔎 학습 리마인드

📌 추가적인 타입

💡 Interface

  • 객체의 구조(Shape)를 정의하는데 사용
interface IUser {
  name: string
  age: number
  isAdult: boolean
}

let user1: IUser = {
  name: 'Neo',
  age: 123,
  isAdult: true
}

💡 Type Alias (타입 별칭)

  • 타입에 이름을 붙이는 문법
  • 객체뿐 아니라 Union, Tuple 등 더 다양한 유형 표현 가능
type User = {
    name: string;
    age: number;
    isValid: boolean;
};

let userArr: User[] = [
    {
        name: "Neo",
        age: 10,
        isValid: true,
    },
    {
        name: "Lewis",
        age: 64,
        isValid: false,
    },
    {
        name: "Evan",
        age: 123,
        isValid: true,
    },
];

💡 Null과 Undefined

  • null → 의도적으로 값 없음을 명시
  • undefined → 값이 아직 정의되지 않음
let undefin: undefined = undefined;
let nul: null = null;

let stringOrNull: string | null = null;
let numberOrUndefined: string | undefined = undefined;

💡 Union (|)

  • A 또는 B의 타입
    let union: (string | number);
    union = 'Hello World';
    union = 777;
    union = false; // Error

💡 Intersection (&)

  • 두 개 이상의 타입을 조합하여 하나의 타입으로 합치는 방식
    • A 이면서 B인 타입

      interface User {
        name: string,
        age: number
      }
      
      interface Validation {
        isValid: boolean
      }
      
      const testCase2: User & Validation = {
        name: 'jisu',
        age: 30,
        isValid: true
      }

📌 타입 어노테이션

  • 변수, 함수, 매개변수, 반환값 등에 명시적으로 타입을 지정하는 문법
    let age: number = 20;
    let name: string = "Neo";
    let isAdult: boolean = true;
    
    // number
    let numbers: number[] = [1, 2, 3];
    let names: string[] = ["a", "b", "c"];
    
    // object
    let user: { name: string; age: number } = {
      name: "Neo",
      age: 30,
    };
    
    // function arguments
    function add(a: number, b: number) {
      return a + b;
    }
    
    // function return
    function getUser(): string {
      return "Neo";
    }

언제 사용하나?

  1. 함수가 any 타입을 리턴하고 이 값을 명확하게 해야 할 때

    const json = '{"a": 1, "b": 2}';
    const object = JSON.parse(json); // any 타입으로 인식 -> 타입 어노테이션 필요
    console.log(object); // {a: 1, b: 2}
    object.asdadsfgsdasdasdasd // 타입스크립트는 object를 any 타입으로 인식해서 이러한 에러를 찾지 못함
  1. 어떤 변수를 선언한 이후 다른 라인에서 초기화 할 때

    const colors = ['red', 'blue', 'green'];
    let foundColor; // 암묵적으로 any 타입을 가짐 -> 타입 어노테이션 필요
    
    for (let i = 0; i < colors.length; i++) {
    	if (colors[i] === 'blue') foundColor = true;
    }
  1. 추론할 수 없는 타입을 변수가 가지려고 할 때

    let numbers = [-10, -5, 10];
    let numberAboveZero = false; // boolean 타입으로 타입 추론 -> 타입 어노테이션 필요 boolean | number
    
    for (let i = 0; i < colors.length; i++) {
    	if (numbers[i] > 0) numberAboveZero = numbers[i]; // error
    }

📌 타입 추론

  • 타입스크립트는 개발자가 타입을 명시하지 않아도 코드의 문맥(Context)을 분석하여 타입을 자동으로 추론해줌

💡 기본 타입 추론

변수의 타입 추론

let num = 10; // number로 추론
let str = "Hello"; // string으로 추론
let bool = true; // boolean으로 추론

배열의 타입 추론

let numbers = [1, 2, 3, 4, 5]; // number[]로 추론
let strings = ["a", "b", "c"]; // string[]로 추론

객체 리터럴 타입 추론

let person = {
    name: "홍길동",
    age: 25
}; // { name: string; age: number }로 추론

person.name = "김철수"; // 정상
person.age = 30; // 정상
person.age = "thirty"; // error: 'string' 형식은 'number' 형식에 할당할 수 없음

함수 반환 타입 추론

function add(a: number, b: number) {
    return a + b; // number로 추론
}

const result = add(5, 3); // result는 number로 추론

💡 컨텍스트를 통한 타입 추론

  • 타입스크립트는 문맥을 통해 타입을 추론할 수 있음

함수 매개변수 반환 타입

let add = (a: number, b: number) => a + b; 
// (a: number, b: number) => number로 추론

콜백 함수 타입 추론

let numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => {
    console.log(num); // num은 number로 추론
});

📌 인터페이스 (Interface)

  • 인터페이스는 객체의 구조(Shape) 를 정의하고, 객체 뿐만 아니라 함수, 클래스 등의 타입을 지정할 때 사용

💡 예제

  • 적용 전
    let person = { name: '홍길동', age: 20 };
    
    function logAge(obj: { age: number }) {
      console.log(obj.age); // 20
    }
    logAge(person); // 20
  • 적용 후
    interface personAge {
      age: number;
    }
    
    function logAge(obj: personAge) {
      console.log(obj.age);
    }
    let person = { name: '홍길동', age: 20 };
    logAge(person);
    • 인터페이스에 정의된 속성만 만족하면, 그 외 속성이 더 있어도 전달 가능

💡 옵션(?) 속성

  • 명시적으로 없어도 되는 속성을 정의할 수 있음
    interface Coffee {
      name: string;
      caffeine?: number;  
    }
    
    let myCoffee = {
      name: "Latte",
    	};
    	
    function brewCoffee(coffee: Coffee) {
      console.log(coffee.name); // Latte
    }
    
    brewCoffee(myCoffee);
    • 옵션 속성caffeine으로 뒀기 때문에 myCoffee 객체에 caffeine 속성이 없어도 됨

💡 읽기 전용 속성 (readonly)

  • 값이 한 번 설정되면 수정 불가
    interface Coffee {
      name: string;
      caffeine?: number;
      readonly brand: string;  
    }
    
    const myCoffee: Coffee = {
      name: "Latte",
      caffeine: 80,
      brand: "Starbucks",
    };
    
    // brand는 readonly이므로 변경 불가
    myCoffee.brand = "Blue Bottle";  // error
    • 인터페이스로 객체를 선언하고 나중에 수정하려고 하면 에러 발생

💡 읽기 전용 배열

  • 배열을 선언할 때 ReadonlyArray<T> 타입을 사용하면 읽기 전용 배열을 생성할 수 있음
    let arr: ReadonlyArray<number> = [1,2,3];
    arr.splice(0,1); // error
    arr.push(4); // error
    arr[0] = 100; // error
    • 읽을 수만 있고, 배열 내용을 변경할 수 없음

💡 객체 선언과 타입 체크

  • 객체 리터럴을 함수를 호출할 때 바로 전달하면 더 엄격하게 검사함 → 실수(오타, 잘못된 속성)를 초기에 잡을 수 있음
  • 객체 리터럴에 없는 속성을 넣으면 오류 발생
    interface Coffee {
      name?: string;
    }
    
    function serveCoffee(coffee: Coffee) {
      console.log(coffee.name);
    }
    
    serveCoffee({ namme: "Americano" }); // error

타입 강제 적용 (as)

  • 타입을 강제로 무시하는 방법
    let cup = {name: "latte"};
    saveCoffee(cup as Coffee); // 강제로 통과

유연한 속성 허용 (인덱스 시그니처)

  • 정해지지 않은 여러 속성을 허용하고 싶을 때
    interface Coffee {
      name?: string;
      [key: string]: any;
    }
    
    const latte = {
      name: "Vanilla Latte",
      size: "Grande",
      shot: 2,
    };
    
    serveCoffee(latte); // OK

📌 인터페이스 vs. 타입 별칭

  • 인터페이스(interface)타입 별칭(type alias)은 기능이 매우 비슷해서 대부분 상황에서 자유롭게 선택할 수 있음

  1. 확장성

    interface Hello {
    	name: string
    }
    
    interface Hello {
    	age: number
    }
    // 가능, Hello 는 name 과 age 모두를 포함하게 됨
    
    type Hello2 = {
    	name: string
    }
    
    type Hello2 = {
    	age: number 
    }
    // 불가능
    • 인터페이스
      • 항상 확장 가능
      • 다른 인터페이스를 상속하거나 동일한 이름으로 다시 열어 새로운 속성을 추가할 수 있음
    • 타입 별칭
      • 한 번 정의되면 다시 열어 새로운 속성을 추가할 수 없음

  1. 복잡한 타입 표현
    • 인터페이스
      • 주로 객체 형태의 타입을 정의하는데 사용됨
    • 타입 별칭
      • 객체 형태 뿐만 아니라 유니온, 튜플, 매칭된 타입 .. 등 복잡한 표현에 유리

0개의 댓글