[러닝타입스크립트]Part2. 특징 - chapter7. 인터페이스

iberis2·2023년 3월 14일
0

타입스크립트

목록 보기
4/7
post-thumbnail

🐰인터페이스

인터페이스는 연관된 이름으로 객체 형태를 설명하는 또 다른 방법이다.
타입 별칭보다 ① 더 읽기 쉬운 오류 메시지 ② 더 빠른 컴파일러 성능 ③ 클래스와의 더 나은 상호 운용성을 가지고 있다.

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

// 두 구문은 거의 같다.
type information = {name: string; age: number; };
interface information2 {name: string; age: number; };

타입 별칭과 인터페이스의 차이점

  • 인터페이스는 속성 증가를 위해 병합할 수 있다.
    • 내장된 전역 인터페이스 또는 npm 패키지와 같은 외부 코드를 사용할 때 유용하다.
  • 인터페이스는 클래스가 선언된 구조의 타입을 확인하는데 사용할 수 있다.
  • 인터페이스에서 타입스크립트 타입 검사기가 더 빨리 작동한다.
  • 인터페이스는 이름 있는(명명된) 객체로 간주되므로 오류 메시지를 좀 더 쉽게 읽을 수 있다.

🥕 속성 타입

여기서 소개하는 속성 타입은 별칭 객체 타입에도 사용할 수 있다.

☘️ 선택적 속성

:?로 생략 가능한 선택적(optional) 속성을 나타낼 수 있다.

interface Book {
  movie?: boolean;
  title: string;
}

const book:Book = {
  movie: true,
  title: '해리포터와 마법사의 돌',
}

const book: Book = {
  title: '러닝 타입스크립트',
}

☘️ 읽기 전용(readonly) 속성

속성 이름 앞에 readonly 키워드를 추가해서,
인터페이스에 정의된 객체의 속성을 재할당하지 못하도록 할 수 있다.

  • 인터페이스에서만 사용할 수 있다.
    • 타입 시스템 구성 요소일 뿐 컴파일 된 자바스크립트 출력코드에 존재하지 않는다.
  • 객체의 인터페이스를 선언하는 위치에서만 사용되고 실제 객체에는 적용되지 않는다.
interface Page { readonly text: string; }

function read(page: Page){
  /* text 속성을 읽는 것은 가능하지만 */
  console.log(page.text);
  
  /* text 속성을 수정하는 것은 에러가 발생한다. */
  page.text += "!";
  // Cannot assign to 'text' because it is a read-only property.
}

☘️ 함수와 매서드

속성 구문: 인터페이스 멤버를 member: () => void와 같이 독립 함수와 동일하게 선언
메서드 구문: 인터페이스 멤버를 member(): void와 같이 객체의 멤버로 호출되는 함수로 선언

interface FuncTypes {
  property: () => string;
  method(): string;
}

const funcObj: FuncTypes = {
  property: () => "",
  method(){ 
    return "";
  }
};

두 구문의 차이점

  • 메서드는 readonly로 선언할 수 없지만 속성은 가능하다.
  • 인터페이스 병합은 메서드와 속성을 다르게 처리한다.
  • 타입에서 수행되는 일부 작업은 메서드와 속성을 다르게 처리한다.

☘️ 호출 시그니처

호출 시그니처는 값을 함수처럼 호출하는 방식에 대한 타입 시스템의 설명이다.
호출 시그니처가 선언한 방식으로 호출되는 값만 인터페이스에 할당할 수 있다.

type FunctionAlias = (input: string) => number;

const funcAlias: FunctionAlias = (input) => input.length;

/* 위와 동일한 타입이다. */
interface CallSignature {
  (input: string): number;
}

const funcCallSig: CallSignature = (input) => input.length

💡호출 시그니처의 interface 부분 잘 모르겠음, 스터디에서 질문하기
() 소괄호가 함수 타입을 나타내는 건가?

  • () 내부는 파라미터 타입, : 오른쪽은 리턴값 타입
interface a {
 (): number
}

☘️ 인덱스 시그니처

인터페이스 객체가 임의의 키를 받고 해당 키 아래의 특정 타입을 반환할 수 있다.
키 다음에 타입이 있고, {[i:string]: ...}과 같이 배열의 대괄호를 갖는다.

interface WordCount {
  [i: string]: number;
}

const counts: WordCount = {};
counts.apple = 0;
counts.banana = 1; 

counts.cherry = false;
// Type 'boolean' is not assignable to type 'number'.

실제 값은 없지만 타입이 정의된 키는 타입 오류가 발생하지 않는다.

interface DateByName {
  [i: string]: Date;
}

const birthday: DateByName = {
  Jeny: new Date('2000.01.01'),
};

birthday.Jeny; // Sat Jan 01 2000 00:00:00 GMT+0900 (한국 표준시)

// 타입은 Date이지만 런타임값은 undefined 이다.
birthday.Kai;

속성과 인덱스 시그니처 혼합

/* 속성의 타입과 인덱스 시그니처의 타입이 같아야 한다. */
interface Book {
  title: string;
  [i: string]: number;
} // Property 'title' of type 'string' is not assignable to 'string' index type 'number'.


/* title을 포함한 1개 이상의 string: string 타입의 프로퍼티가 있어야 한다.*/
interface Book {
  title: string;
  [i: string]: string;
}

const novel: Book = {
  title: '해리포터와 불의 잔',
  author: '조앤K.롤링'
}

/* title만 있어도 ok */
const novel2: Book = {
  title: '해리포터와 불사조 기사단',
}

/* string: string 타입의 프로퍼티가 있어도, 
타입에 정의된 title 속성은 반드시 있어야 한다. */
const novel3: Book = {
  author: '조앤K.롤링'
} // Property 'title' is missing in type '{ author: string; }' but required in type 'Book'.

숫자 인덱스 시그니처
💡잘 모르겠는 부분

/* 가능 */
interface Book {
  [i: number] : string | undefined;
  [i: string]: string | undefined;
}

/* 가능 */
interface Book {
  [i: number] : string;
  [i: string]: string | undefined;
}

/* 오류 */
interface Book {
 [i: number] : string | undefined;
 [i: string]: string;
} // 'number' index type 'string | undefined' is not assignable to 'string' index type 'string'.

☘️ 중첩 인터페이스

interface Book {
  title: string;
  author: Author;
}

interface Author {
  name: string;
  famous: boolean;
}


const HarryPoter: Book = {
  title: '해리포터와 마법사의 돌',
  author: {
    name: '조앤K.롤링',
    famous: true,
  }
}

🥕 인터페이스 확장

다른 인터페이스의 모든 멤버를 포함하고, 거기에 몇 개의 멤버가 추가된 인터페이스인 경우

  • 이름 뒤에 extends 키워드를 추가한다.
interface Person {
  name: string;
  age: number;
}

interface Friend extends Person {
  school: string;
}

/* Person 과 Friend에 있는 모든 속성을 가지고 있어야 하며, 그 외 추가 속성(프로퍼티)은 가질 수 없다.*/
const friend: Friend = {
  name: 'Janny',
  age: 15,
  school: 'K-highschool'
}

☘️ 재정의된 속성

interface Person {
  name: string | null;
}

// 타입을 더 구체적인 하위 집합으로 만드는 것은 가능하지만
interface Friend extends Person {
  name: string;
}

// 다른 타입으로 확장하거나 바꾸는 것은 오류가 발생한다.
interface classMate extends Person {
  name: number | null
} 
/* Interface 'classMate' incorrectly extends interface 'Person'.
    Types of property 'name' are incompatible.
      Type 'number | null' is not assignable to type 'string | null'.
        Type 'number' is not assignable to type 'string'.*/

☘️ 다중 인터페이스 확장

extends 키워드 뒤에 쉼표,로 인터페이스 이름을 구분해 사용하면 여러 개의 다른 인터페이스를 확장해서 선언할 수 있다.

interface Person {
  name: string | null;
}

interface Greeting{
  sayHello(): string;
}

// 여러 인터페이스를 확장할 수 있다.
interface Friend extends Person, Greeting {
  phone: number;
}

function friend(input: Friend){
  console.log(`${input.sayHello()} ${input.name}, Call ${input.phone}.`);
}

let friend1 = {
  name: 'Jay',
  sayHello: () => `Hi!`,
  phone: 777
}

friend(friend1); //  "Hi! Jay, Call 777."

🥕 인터페이스 병합

두 개의 인터페이스가 동일한 이름으로 동일한 스코프에서 선언된 경우, 선언된 모든 필드를 포함하는 더 큰 인터페이스가 코드에 추가된다.

  • 코드를 이해하기 어려워지기 때문에 가능하면 인터페이스 병합을 사용하지 않는 것이 좋다.
  • 단, 외부 패키지 또는 Window 같은 내장된 전역 인터페이스를 보강하는데에 유용하다.
interface Same {
  first: string;
}

interface Same {
  second: number;
}

// interface Same { first: string; second: number; } 와 같다.

const sameObj: Same = {
  first: 'one',
  second: 1
}

☘️ 이름이 충돌되는 멤버

동일한 이름이지만 타입이 다른 속성을 선언할 수 없다.

  • 단, 동일한 이름과 다른 시그니처를 가진 메서드는 정의할 수 있다.
    이 경우, 메서드에 대한 함수 오버로드가 발생한다.
// first 는 동일한 string 타입이므로 문제 없지만,
// second는 타입이 다르기 때문에 오류가 발생한다.
// third는 메서드이므로 문제 없다.
interface Same {
  first: string;
  second: string;
  third(input: string): string;
}

interface Same {
  first: string;
  second: number;
  third(input: boolean): number;
}
// Subsequent property declarations must have the same type.  
// Property 'second' must be of type 'string', but here has type 'number'.

☘️

🥕

profile
React, Next.js, TypeScript 로 개발 중인 프론트엔드 개발자

0개의 댓글

관련 채용 정보