타입스크립트에서 객체 타입을 정의할 때 사용하는 문법입니다.
인터페이스를 사용하여 객체의 속성과 들어갈 데이터 타입을 정확하게 정의할 수 있습니다.
interface
키워드를 사용해서 정의합니다.interface Profile {
name: string,
age: number,
address: string,
}
let jon: Profile = {
name: "jon",
age: 20,
address: "seoul",
}
// 에러 발생: age의 타입이 interface에 선언한 타입과 불일치
let mike: Profile = {
name: "mike",
age: "20",
address: "Busan"
}
// 에러 발생: address가 존재하지 않음 interface의 객체 속성과 불일치
let jane: Profile = {
name: "jane",
age: 20
}
// 에러 발생: interface에 존재하지 않는 객체 속성 hobby가 추가됨
let bob: Profile = {
name: "bob",
age: 20,
hobby: "shopping"
}
1 ) 함수 파라미터 정의 방법
interface Food {
name: string,
prcie: number,
}
function foodInfo(someFood: Food) {
console.log(someFood.name, someFood.price)
}
let pizza = {name: "pizza", "15000"}
foodInfo(pizza) // 'pizza', 15000
2 ) 함수의 반환 타입 정의 방법
interface Food {
name: string,
prcie: number,
}
function foodInfo(someFood: Food): Food {
retrun pizza
}
let pizza = {name: "pizza", "15000"}
foodInfo(pizza) // {name:'pizza', prcie: 15000}
인터페이스 속성 중 하나만 꼭 필요한 속성이고, 나머지 속성은 필요하지 않을 수 있는 속성일 경우 어떻게 정의해야 할까요?
타입스크립트에서는 타입과 객체의 속성이 일치하지 않으면 에러가 발생합니다.
인터페이스에서 옵션 속성(?)을 통해 객체의 속성을 꼭 받을 필요 없도록 설정할 수 있습니다.
옵션 속성은 상황에 따라 유연한 인터페이스 속성의 사용 여부를 결정할 수 있게 해줍니다.
interface Profile {
name: string,
age: number,
address?: string, // 옵션 속성 사용 해당 값에 들어갈 수도 안들어갈 수도 있음
}
// 옵션 속성을 사용하여 address 값이 없어도 에러가 발생하지 않는다.
let jon: Profile = {
name: 'jon',
age: 20
}
extends
키워드를 사용하여 상속할 수 있습니다.interface Person {
name: string,
age: number,
}
// Person 인터페이스를 상속(name, age)
interface Developer extends Person {
skill: string;
}
// Devloper 인터페이스는 Person 인터페이스를 상속 받아 name과 age 속성 타입이 정의됨
let jon: Developer = {
name: 'jon',
age: 21,
skill: 'typescript'
}
interface Person {
name: string,
age: number,
}
// age 타입이 상속 받은 Person age의 타입과 일치하지 않아 에러발생
interface Developer extends Person {
age: string,
skill: string;
}
인터페이스로 객체와 배열의 인덱싱 타입을 정의할 수 있습니다.
인덱싱이란 객체의 특정 속성을 접근하거나 배열의 인덱스로 특정 요소에 접근하는 동작을 의미합니다.
배열의 인덱싱은 대괄호([ ])에 해당되는 인덱스를 넣어 사용합니다.
객체의 인덱싱은 대괄호([ ]) 프로퍼티 연산자를 사용합니다.
객체는 대괄호 프로퍼티 연산자를 사용할 때 대괄호 안에 해당 속성의 키값을 넣게됩니다.
let user = {
name: 'jon',
age: 20,
}
// 대괄호 프로퍼티 연산자를 사용하여 인덱싱하여 값에 접근
// user.name, user.age와 같은 기능
console.log(user['name'], user['age']);
let companies = ['네이버', '토스', '당근마켓']
console.log(companies[0]) // 네이버
interface StringArray {
[index: number]: string;
}
let companies:StringArray = ['네이버', '토스', '당근마켓']
interface Menu {
[name: string]: number;
}
let foodMenu: Menu = {
pizza: 15000,
cola: 2000
}
let prcie = foodeMenu['pizza']; // 15000
위에서 객체의 인덱싱을 통해 인터페이스를 정의했습니다.
객체의 인덱싱을 통해 타입과 속성 값을 정의한 것을 인덱스 시그니처라고 부릅니다.
interface Menu {
[name: string]: number;
}
let foodMenu: Menu = {
pizza: 15000,
cola: 2000,
chicken: 15000,
hamburger: 8000,
// .
// .
// .
// 객체 안에 무수히 많은 속성이 있더라도 추가가 가능
}
여러 개의 타입 중 한 개의 타입을 사용하고 싶을 경우 사용하는 문법입니다.
유니온 타입은 중복된 코드를 줄이고, 타입을 더 정확히 선언할 수 있습니다.
유니언 타입은 | 연산자를 사용하여 선언하는 방식입니다.
아래 예시 코드에서 문자열, 숫자형 타입 모두 넘기고 싶을때는 유니온 타입을 사용할 수 있습니다.
function logText(text:string | number) {
console.log(text);
}
logText('hi');
logText(10);
만약 유니언 타입이 없었다면 any 타입을 사용하지 않고서는 아래와 같이 두 개의 함수를 정의해야했을겁니다. 이런 경우 동일한 동작을 하는 함수이지만 타입만이 달라서 코드를 중복해서 작성해야한다는 매우 불편한 단점이 있습니다.
따라서 유니언 타입 사용은 중복된 코드를 줄일 수 있습니다.
function logText(text:string) {
console.log(text);
}
function logNumber(text:number) {
console.log(text);
}
logText('hi');
logNumber(10);
그럼 만약 유니언 타입을 사용하지 않고 any타입을 사용한다면 어떻게 될까요?
물론 any 타입을 사용하면 정상적으로 동작할 수 있습니다.
하지만 any 타입의 경우에는 모든 타입이 들어갈 수 있기 때문에 예측하지 못할 동작을 할 가능성이 생기며, 이는 타입스크립트를 사용하는 의미가 사라지게 됩니다. 또한, 타입스크립트의 타입이 정해져 있을 때 자동으로 속성과 API를 완성하는 기능을 사용할 수 없습니다.
따라서 유니언 타입 사용은 원하는 타입들 만을 더 정확히 선언할 수 있도록 해줍니다.
function logText(text:any) {
console.log(text);
}
logText('hi');
logNumber(10);
유니온 타입 사용시 함수에 어떤 값이 들어올지 알 수 없습니다.
어느 타입이 넘어올지 알 수 없기 때문에 문제가 없는 공통된 속성만 사용할 수 있습니다.
interface Person {
name: string;
age: number;
}
interface Devloper {
name: string;
age: number;
skill: string;
}
// 에러 발생 Person에는 skill 타입이 없기 때문에
function introduce(someone: Person | Developer) {
console.log(someone.skill);
}
만약 공통된 속성이 아닌 해당 타입에 존재하는 속성을 사용하고 싶을 경우에는 in 연산자를 사용해서 로직을 작성하면 됩니다.
in 연산자는 객체 특정 속성이 있는지 확인하는 자바스크립트 연산자입니다.
if문 안에 in 연산자를 사용하면 해당 속성이 있는 타입으로 간주됩니다.
이렇게 동작하는 방식을 타입가드(type guard) 라고 합니다. 타입가드의 내용은 추후 다루도록 하겠습니다.
interface Person {
name: string;
age: number;
}
interface Devloper {
name: string;
age: number;
skill: string;
}
// in 연산자를 사용하여 someone 타입을 Developer 타입을 간주
function introduce(someone: Person | Developer) {
if('skill' in someone) {
console.log(someone.skill);
}
}
인터섹션 타입은 두 개의 타입를 하나로 합쳐서 사용할 수 있는 타입입니다.
주로 인터페이스 2개를 합치거나 타입 정의 여러 개를 하나로 합칠 때 사용합니다.
합친 두 타입 속성 중 하나라도 빠지면 에러가 발생합니다.
interface Person {
name: string;
age: number;
}
interface Devloper {
name: string;
age: number;
skill: string;
}
function introduce(someone: Person&Developer) {
console.log(someone.name, somone.age, someone.skill);
}
let jon = {
name: 'jon',
age: 20,
skill: 'typescript'
}
let mike = {
name: 'jon',
age: 20,
}
introduce(jon) // 'jon', 20, 'typescript'
// 에러 발생 skill 속성이 없음
introduce(mike)
- 인터페이스는 객체 타입을 정의하기 위해서 사용되는 문법입니다.
- 인터페이스에서는 옵션속성을 사용하여 필요한 속성만을 정의하도록 할 수 있으며, 상속을 사용할 수 있습니다.
- 인터페이스를 인덱스 타입으로 정의하여 인덱스 시그니처 구현해 직접 인터페이스에 객체 타입을 지정하지 않아도 무수히 많은 속성 타입들을 추가할 수 있습니다.
- 유니온 타입은 여러 개의 타입 중 한 개의 타입을 사용하고 싶을 경우 사용하는 문법입니다.
- 유니온 타입은 중복된 코드를 줄이고, 타입을 더 정확히 선언할 수 있습니다.
- 인터섹션 타입은 두 개의 타입를 하나로 합쳐서 사용할 수 있는 타입입니다.
- 주로 인터페이스 2개를 합치거나 타입 정의 여러 개를 하나로 합칠 때 사용합니다.