A+B=>A'
상속을 통해 중복되는 타입 name
과 age
의 중복을 피할 수 있다.
interface Person{
name: string;
age?:number;
}
interface Developer{
name: string;
age?:number;
skill : string[]
}
상속받고자 하는 타입을 extends
로 받아올 수 있다.
interface Developer extends Person{
skill: string[]
}
상속받고자 하는 타입을 선언하고 &
연산자를 표기한 후 자신의 타입을 지정한다.
type Person = {
name: string;
age?: number;
job?: string;
}
type Developer = Person & {
skill : string[]
}
type barista = Person['job'] //string type
A+B=>C
이미 존재하는 타입 여러개를 하나의 타입으로 만들 때 사용된다.
상속으로 구현할 수도 있겠지만 상속받은 타입에서 상속된 타입을 필요로 하지 않는 경우에 타입에러의 가능성이 발생할수도 있기 때문에
자신의 타입은 고수하면서 새로운 병합된 타입
을 만드는 것이다.
병합시킬 땐 A&B
형태로 선언하고, 이는 interface
이든 type Alias
든 동일하다.
interface Cafe{
menu: string[]
}
interface Bank{
money: number[]
}
const cafe:Cafe = {menu:['coffee', 'milk']}
const bank:Bank = {money:[100,200]}
const cafeManuel = (cafe:Cafe, bank:Bank): Cafe&Bank => ({...cafe, ...bank})
const newCafe = cafeManuel(cafe, bank)
console.log(newCafe)
/* {
"menu": [
"coffee",
"milk"
],
"money": [
100,
200
]
}
*/
type Alias
가 더 효과적이다.type Color = "red" | "purple" | "orange";
const color: Color = "orange";
color를 선언할 때 3가지 색 중에 한가지만 선택할 수 있도록 탭이 떠서 선택이 가능하다.
반면, interface에서는 key값이 요구되기 때문에 객체 형태의 데이터 속성에 유니온타입을 줄 때 사용할 수 있다.
interface Color2 {
color: "red" | "purple" | "orange";
}
const color2: Color2 = { color: "purple" };
index타입은 타입선언을 JavaScript처럼 좀 더 유연하게 줄 수 있는 타입이다. 이는 객체형 타입을 나타내므로 type Alias
와 interface
모두 작성법이 동일하다.
interface Props {
name: string;
age: string;
[key: number]: string;
}
const testObject: Props = {
1: "13",
2: "23",
3: "33",
name: "namju",
age: "50",
};
console.log(testObject.age); //50
console.log(testObject["1"]); //13
console.log(testObject[1]); //13
key에는 오로지 string 과 number 타입만 지정할 수 있다.✨
[key: number]: string;
는 number 타입의 키와 string 타입의 값을 갖는 타입을 의미하고, name
과 age
라는 키를 필수로 가져야함을 나타낸다. 숫자와 name, age 외의 키 값을 선언하면 타입에러가 생긴다.
또한, 전체적인 인덱스 타입의 형태에 맞춰지는데 만일, age
의 값으로 number로 주는 것은 불가능하다. number를 지정하고 싶다면
인덱스타입의 값이 string|number
타입으로 변경되어야 한다.
타입의 key값을 keyof
로 접근할 수 있다.
let keyOfObjects: keyof Props;
keyOfObjects = "age";
console.log(testObject[keyOfObjects]);//50
keyOfObject에 올 수 있는 값은 1, 3, name, age 외 기타 숫자 타입의 key값이다. 기타 숫자 타입의 키가 올 수 있는 것은 인덱스 타입의 키를 number로 지정했기 때문이다.
type error case 1) age, name 외의 string 지정
let keyOfObjects: keyof Props;
keyOfObjects = "address";
//Type '"address"' is not assignable to type 'keyof Props'.
type error case 2) testObject에 존재하지 않는 key지정
let keyOfObjects : keyof Props;
keyOfObjects = 7 //-> 타입선언은 가능
console.log(testObject[keyOfObjects]) //undefined
기존의 타입들은 interface
이든 Alias
인지 상관없다.
기존 객체형 타입의 key로 접근하여 해당 type을 재사용 할 수 있다.
type Alias
가 사용된다.interface Person {
name: string;
age?: number;
job?: string;
}
interface Developer extends Person {
skill : string[]
}
type Barista = Person['job'] //string type
const barista:Barista = 'coffee maker'
interface
를 사용할 수 있는 경우는 역시 객체형 데이터 일때이다.interface Person {
name: string;
age?: number;
job?: string;
}
interface Developer extends Person {
skill : string[]
}
interface Barista {
result: Person['job'] | Person['age'] //string or number
}
const barista:Barista = {result: 100}
interface
는 type을 중복하여 작성할 수 있고 확장성에 유리하다.✨
interface Test{
score: number
}
interface Test{
title: string
}
const prevTest:Test = {score: 500} // typeError
const mainTest:Test = {title: 'math', score:100}
type Alias는 중복하여 작성할 수 없다.
type Test = {
score: number
}
type Test = {
title: string
}
//Duplicate identifier 'Test'.
이러한 이유로 확장성이 요구되는 public API, 3rd party 라이브러리와 관련된 프로젝트에서는
interface
를 사용하는 것이 좋다. 때문에 interface를 사용하면서 원시형 데이터에 union type을 지정하는 경우 등에 type Alias를 사용하도록 타입스크립트에서 권장한다고 한다.
하지만 일반적인 리액트 프로젝트에서 위와 같은 Declaration Merging
을 사용할 일은 거의 없으므로 사용자의 기준에 따라 일관성을 갖고 쓰는 것이 좋다.
Object
, Interface
, type Alias
3가지를 모두 사용할 수 있다.//Object : 재사용 x
function SampleComponent(sample:{name: string, age:number}){
....
}
//Interface
Interface SampleProps{
name: string
age: number
}
fuction SampleComponent(sample: SampleProps){
...
}
참고하면 좋을 자료들
interface-vs-type-alias-in-typescript