오늘 간단하게 타입스크립트 개념을 공부하다가 비슷한 둘을 만나서 이펙티브 자바스크립트에서 찾아보니 관련 글이 있어서 정리하려 한다.
그전에 간단하게 오늘 공부한 타입스크립트 타입들에 대해 정리하고 가야겠다. 그중 기억에 남는 건 인덱싱이랑 딕셔너리 패턴인데 다음과 같다.
//인덱싱
interface StringArray{
[index:number]:string;
}
var arr: StringArray = ['a','b','c'];
arr[0]="new"
interface originArray{
[index:number]:number
}
var arr2:originArray=[]
//딕셔너리 패턴
interface StringRegesDictionary{
[key:string] : RegExp
}
var obj : StringRegesDictionary={
sth:/abc/,
cssFile:/\.css$/,
jsFile: /\.js$/
}
인덱싱은 기존에 알던 배열을 단순히 number[], Array <number> 뭐 이런 식으로 해도 되지만 인터페이스로 위와 같이 적을 수도 있다
근데 이거보다 실용적으로 딕셔너리 패턴으로 쓸거 같은데 위의 코드 예시는 정규표현식을 값으로 하는 딕셔너리 객체 타입이다. RdgExp는 내가 선언한 게 아니라 원래 있는 interface이다. 다음과 같다.
인터페이스는 위에서 코드 보면서 봤겠지만, 내가 작성하려는 객체의 프로퍼티들의 타입을 설명해주고 있다. 타입 또한 같은 형태로 만들어진다. 함수 타입도 다음과 같이 설정할 수 있다.
코드상에서 타입과 인터페이스의 차이점을 보면 에디터에 마우스를 가져가보면 타입은 내부의 프로퍼티를 자세하게 표현해 준다. 또한 확장면에서 차이가 조금 있는데, 둘다 확장을 할 수 있다.
하지만 인터페이스는 기존에 내가 선언한 인터페이스나 타입을 가지고 extends를 통해 확장하지만 타입 같은 경우 별칭이기 때문에 내가 그 별칭에 인터페이스를 할당하거나 인터섹션 또는 유니온을 사용해서 확장한다.
그리고 타입은 인터페이스와 다르게 복잡한 타입을 확장 할 수 있다. (근데 여기서 보면 타입이 확장을 한다는말이 내 생각에는 확장이라기보다는 그냥 새로운 타입 가지고 또 다른 타입 만들어서 받는 느낌이다. 근데 뭐 이것도 확장은 맞으니까).
복잡한 타입을 확장하지 못하는것도 인터페이스끼리는 유니온을 할 수 없어서 그렇다. 그니까 type은 말 그대로 타입 별칭이어서 별의별 타입을 다 막 붙여서 쓸 수 있다. 다음과 같다.
type NamedVariable = (Input | Output) & {name:string};
그래서 일반적으로 type이 인터페이스보다 쓰임이 많다고 한다. 튜플과 배열 타입도 막 표현할 수 있으니까.
여기까지 보면 귀찮으니까 type 쓰면 되겠네 하겠지만, 아직 interface의 특징이 남았다.
인터페이스는 타입에 없는 기능들이 있는데 그중 하나가 바로 augument가 가능하다는 것이다. 밑의 예시를 보자
interfacec IState{
name:string;
capital:string;
}
interface IState{
population:number;
}
const Kim: IState ={
name:"Kim",
capital: "Seoul",
populaation: 500000
}
이 예제처럼 속성을 확장하는 것을 declaration merging(선언 병합)이라고 한다. 따라서 선언 파일을 작성 할 때는 선언 병합을 지원하니까 반드시 인터페이스를 사용해야 하며 표준을 따라야 한다.
타입스크립트는 여러 버전의 자바스크립트 표준 라이브러리에서 여러타입을 모아 병합한다. 예를 들어, Array 인터페이스는 lib.es5.d.ts에 정의되어 있고 기본적으로 여기에 있는 인터페이스가 사용된다. 그러나 tsconfing.json lib목록에 ES2015를 추가하면 타입스크립트는 lib.es2015.d.ts에 선언된 인터페이스를 병합한다. 병합은 선언과 마찬가지로 일반적인 코드에서도 지원되므로 언제 병합이 가능한지 알고 있어야 한다. 타입은 기존 타입에 추가적인 보강이 없는 경우에만 사용해야 한다.
마지막으로 정리하겠다.
복잡한 타입이라면 고민할 것도 없이 type을 사용하면 되고, type 또는 interface로 표현할 수 있는 간단한 객체 타입이면 일관성과 보강의 관점에서 고려해 봐야 한다. 일관되게 인터페이스를 쓰면 당연히 인터페이스를 써야 하고 type이라면 type을 쓰면 된다. 아직 스타일이 확립되지 않은 프로젝트라면 향후에 보강 가능성이 있는지 생각해봐야 한다. 그리고 보통 API에 대한 타입 선언을 작성해야 한다면 인터페이스가 좋다고 한다. API가 변경될 때 사용자가 인터페이스를 통해 새로운 필드를 병합할 수 있어 유용하기 때문이다. 그러나 프로젝트 내부적을 사용되는 타입에 선언 병합이 발생한 경우는 잘못된 설계라고 볼 수 있다.
내 생각을 한 번 더 이야기하자면 확장이라는 게 조금 헷갈리는데 솔직히 type 같은 경우 그냥 여러 타입들을 별칭으로 정하는 거여서 내 느낌에는 확장보다는 진짜 별칭으로 정하는거 같고 interface가 좀 더 확장이라는 단어가 어울린다.
참고 및 출처: <이펙티브 타입스크립트> (댄 밴더캄 지음, 장원호 옮김, 인사이트 ,2021) , <타입스크립트 입문> (인프런 강의 , 장기효)
'TIL' 카테고리의 다른 글
TS. Generics 그리고 코드 중복에 관해 (0) | 2022.01.26 |
---|---|
PS. FenwickTree 그전에 SegmentTree (0) | 2022.01.25 |
TS. 타입스크립트 시작전에 (0) | 2022.01.19 |
DOM. 관련 개념 정리 (0) | 2022.01.19 |
JS. this (0) | 2022.01.19 |