11 분 소요

다른 글들과는 달리 이번 글은 개인적인 경험들로 작성된 서론이 다소 길다는 점 참고바랍니다.

백엔드든 프론트엔드든 가리지 않고 필요하다면 학습하고자 하는 의지가 있다. 다만 백엔드가 내게 더 맞다고 생각한 것도 있고, “두 마리 토끼 잡으려다가 둘 다 놓친다”라는 말처럼 선택과 집중을 하는 것도 중요하다고 생각하였기에 지금까지 백엔드 위주로 공부해왔다. 그럼에도 내가 개발한 기능을 사용자에게 보여주고자 한다면 웹 앱을 구현할 수도 있어야 하기에 프론트엔드도 공부해왔다. 현재는 “사용자에게 무언가를 보여줄 수 있느냐”와 같이 “구현”을 우선순위로 두고 있어서 프론트엔드는 최소한의 핵심적인 개념들에만 집중해서 학습, 정리해오고 있다.

사실 단순하게 생각해보면 웹 사이트, 웹 애플리케이션을 “보여준다”라는 것에만 초점을 맞춘다면 HTML, CSS, Javascript만 알아도 충분할 것이다. 실제로 필자는 이전에 이 세 가지 기술만으로 계산기, 투두 리스트, 시계, 달력 등 자잘한 기능들을 하나하나 구현한 뒤 이를 단 하나의 사이트에서 편하게 사용하기 위한 목적의 사이트를 만들어 본 경험이 있었다.

Github repo: https://github.com/JeroCaller/boardaily/tree/without-using-api

Web Site: https://jerocaller.github.io/boardaily/

또한 학원에 다닐 당시에도 오로지 HTML, CSS, Javascript만으로 외부 API를 호출하여 가져온 데이터들을 토대로 화면에 렌더링해보는 연습들도 해본 적이 있었다. 그런데 이 두 경험을 겪어보니 생각보다 이 기본 기술만으로 구현하고자 하는 바를 쉽게 구현하기가 어려웠었다. 특히 외부 API를 AJAX 요청으로 가져와 UI로 렌더링하는 과정은 말로만 듣기에는 쉬워보이지만 막상 요구사항이 조금만 복잡해져도 코드가 굉장히 난잡해지고 구현 난이도도 상승하던 것을 겪었었다.

그런데 리액트를 공부하고 이를 사용하다보니 그러한 애로사항이 눈에 띌 정도로 줄어들었다. 코드가 상대적으로 더 짧아지고 구현 난이도도 낮아졌으며, 또한 웹 화면을 구성하는 여러 UI 요소들을 컴포넌트 단위로 나눠 개발할 수 있기에 구현하고자 하는 핵심 로직에만 집중할 수 있는 환경이 조성된다는 점, 가독성 및 유지보수성을 얻을 수 있다는 점이 큰 매력으로 다가왔었다. 그래서 솔직히 지금 다시 Vanila JS로 돌아가라고 하면 그러지 못할 것 같다. 개인적으로는 리액트의 “상태(state)”라는 개념과 JSX라는 직관적인 문법 덕분에 데이터와 UI의 구분이 쉬워졌기에 이러한 장점이 부각되지 않았나, 라는 생각이 든다. 반대로 말하면 기존의 자바스크립트만으로는 외부에서 가져온 데이터와 UI의 구분이 뚜렷해보이지 않았고, 더군다나 document.querySelector 등 DOM에 직접 접근하는 방식이다보니 UI 코드가 JSX에 비해서 훨씬 비직관적이었다는 것도 구현 어려움에 한몫했다는 생각이 든다.

이러한 경험은 내가 아무리 백엔드에 집중을 하더라도 가독성, 유지보수성, 개발자 경험 등의 여러 요소들을 위해서라면 기꺼이 시간을 내어서라도 리액트 등 프론트엔드도 어느 정도는 투자하는 게 오히려 내게 더 이득이라는 생각이 들게 하였다. 그리고 최근까지 리액트의 기초, 핵심 개념들에 대해 정리하면서 이 생각이 또 한 번 들게 되었다.

사실 자바스크립트와 리액트를 겪어오면서, 마치 가랑비에 옷이 서서히 젖어가듯 스멀스멀 들었던 불편함이 있었다. 그건 바로 자바스크립트가 기본적으로 동적 타입 언어라는 것이었다. 자바라는 언어는 정적 타입 언어였기에 모든 변수, 메서드의 매개변수 하나하나 모두 다 타입을 미리 선언해야하는 것이 귀찮게 느껴질지 몰라도, 그 덕분에 변수에 어떤 타입의 값을 넣어야 할지, 메서드의 어떤 파라미터에 어떤 타입의 값을 넣어야 할지 쉽게 파악이 되어 개발하기가 오히려 편했다는 느낌이 들었다. 그런 느낌을 자바스크립트에서는 전혀 느끼질 못했다. 그 중에서도 의외로 특히 더 불편하다 느낀 지점이 “이벤트 핸들러” 함수를 작성할 때였다.

/**
 * 
 * @param {Event} event 
 */
const handleInputChange = event => {
  console.log(event.target.value);
  setUsername(event.target.value);
};

코드 1-1. 예시 코드.

지금이야 JSDoc 주석을 통해서라도 event 파라미터의 타입을 명시할 수 있지만, 이조차도 몰랐던 때에는 “저 이벤트 객체에는 어떤 속성들이 있는거지?”란 생각으로 일일히 console.log 함수를 작성하면서 콘솔창에서 매번 확인해야 했던 적이 있었다. 사실 정적 타입 언어의 장점 중 하나는 VSCode나 IntelliJ와 같은 IDE에서 자동완성 기능을 지원해주기에 특정 객체에 어떠한 메서드나 필드들이 있는지 일일히 하나하나 소스코드까지 살펴볼 필요를 많이 줄여준다는 것이다. 자바스크립트는 그러한 언어가 아니다보니 가끔 내가 필요한 기능에 어떻게 접근해야할지 몰라 콘솔창에 일일히 로그 메시지 찍어가면서 파악해야했던 것이다.

이러한 불편함은 위 코드 1-1와 같이 JSDoc, 쉽게 말해 주석 기능을 사용하면 어느 정도 해결은 되었다. 하지만 정적 타입 언어에서 타입 이름만 명시하면 되었던 것에 비하면 주석까지 써야하는 것이 어쩐지 장황하다고 느껴졌다(특히나 별도로 작성할 설명글이 없다면 더더욱).

그럼에도 아직 자바스크립트나 리액트를 완전히 학습한 것은 아니기도 하고, 백엔드에 집중해야하기도 해서 그동안 이 문제에 대해서는 그냥 감안하고 사용해왔다.

하지만 리액트를 공부하고 예제 프로젝트들도 간단하게 만들어보면서 이러한 동적 타입의 불편함이 줄어들기는 커녕 점점 더 늘어만 갔다. 자바라는 정적 타입 언어를 주로 사용해와서인지 왜인지는 모르겠지만, 그러한 불편함이 이젠 불만으로 변해가기 시작했다. 그래서 리액트의 필수적인 개념들을 정리한 다음 원래는 바로 개인 프로젝트로 넘어가려고 했지만, 시간 절약을 위해 바로 프로젝트로 넘어갈 것인지, 아니면 시간을 투자해서라도 이러한 불편함을 해결할 것인지 고민되었다. 가독성, 유지보수성, 개발자 경험도 중요하지만, 어떤 새로운 것을 배우는 데에 필요한 시간과 진입장벽도 무시 못한다고 생각하였기에 고민을 했던 것이다. 조금이라도 시간을 아껴 바로 프로젝트로 진입하느냐, 아니면 그러한 시간을 희생하더라도 조금 더 관련 학습을 할 것인가.

고민 끝에 결국 나는 후자를 택했다. 이거 안하고 프로젝트 시작하면 답답함이 계속 날 따라올 것이다, 와는 별개로 다음의 요인들이 있었기 때문이다.

  • 프로젝트 진행 시 프론트 쪽에서는 Bootstrap, MUI, Chakra 등 이미 존재하는 UI component library를 사용할 생각이다. 지금까지 겪어본 바로는 각자 라이브러리들에서 자체적으로 정의하는 객체, 함수 파라미터들이 있는데, 처음에 “이 객체들을 어떻게 사용해야하지?”로 인해 공식 문서를 통해 파악하는 시간이 필요했다. 파악하고 나서 이를 타입으로 정의해두면 나중에 까먹어도 그 타입만 보고도 바로 이해할 수 있지 않을까, 란 생각이 들었다. 즉, 외부 라이브러리의 원활한 사용을 위해선 “타입”이란 것이 반드시 필요하다고 봤기 때문이다.
  • 백엔드에서 JSON 형태의 응답을 프론트 측으로 보내는 REST API를 구축하고, 프론트에서 이를 받을 때 JSON 객체 내 각 속성들의 타입이 무엇인지를 타입으로 미리 정의할 수 있다면 사용하기도 편하고, 나중에 다시 코드를 봤을 때 이 코드가 무엇인지 이해하려고 노력해야하는 과정을 최소화할 수 있지 않을까, 란 생각이 들었다. 즉 백엔드와 프론트엔드 간 의사소통에도 타입 정의가 어느 정도 역할을 할꺼란 생각이었다.
  • 코드 자동 완성 기능을 사용할 수 있게 된다. 앞서 “이벤트 핸들러” 사례에서도 언급했듯, 이게 있고 없고 차이가 개발자 경험 및 생산성 측면에서 은근 크다고 본다.
  • 이건 농담반 진심반이지만, 정적 타입 언어인 자바를 주로 사용해온만큼 프론트에서도 정적 타입 형태로 코드를 작성한다면 제3자가 보았을 때 일관성 있고 유지보수를 중요하게 여기는 사람이라고 보이지 않을까? 이건 내가 과하게 생각하는 것일지도 모르지만 만약 한 쪽에선 자바라는 정적 타입 언어를 사용하는데, 또 한쪽에서는 막상 타입 상관 안하고 코드를 작성한다면 어딘가 모순이 느껴지지 않을까, 란 생각이 들기도 한다.

결국 타입으로 인한 에러 방지, 가독성 및 나중을 위한 유지보수성이 생각보다 중요하다고 느꼈기에 결국 타입스크립트를 학습하게 되었다.

서론이 많이 길었다. 지금까지는 “내가 타입스크립트를 학습할 수밖에 없었던 이유”를 내 개인적인 느낌, 경험에 빗대어 설명하였다. 이제부터는 타입스크립트가 무엇인지 개요 수준으로 살펴보고자 한다. 기본적인 개념들은 은근 그 양이 많아 다음 글에 작성할 계획이다. 다만 타입스크립트의 경우 먼저 내용 깊숙히 학습한다기보다는 핵심만 공부한 뒤, 프로젝트를 진행하면서 필요하게 되면 그때그때 배워가고 정리할 생각이다.

TypeScript

옛날에는 지금처럼 웹의 규모가 그리 크지 않았기에, 주로 간단한 기능을 빠르게 만들 수 있도록 하는 스크립트 형태의 자바스크립트라는 언어가 탄생되어 사용되어 왔다고 한다. 그러다보니 자바스크립트는 이러한 간결성을 유지하기 위해 동적 타입 언어로 만들어졌다고 한다.

그러나 시간이 지나며 웹의 규모가 커지면서 이러한 자바스크립트의 동적 타입의 특성이 서서히 문제가 되어갔다. 대규모 프로젝트나 협업을 해야하는 상황에서는 이러한 동적 타입이 오히려 개발에 발목을 잡았다. 변수나 함수의 매개변수를 정의하고 사용할 때 협업, 또는 장기적인 유지보수가 필요한 프로젝트라면 타입이 있어야 코드 이해가 수월한텐데 그게 없으니 불편한 것이다. 오타, 또는 잘못된 타입의 값을 사용하더라도 이로 인한 에러가 컴파일 단계가 아닌 런타임 단계, 즉 실행하고 나서야 발견할 수 있기에 동적 타입의 특성은 오히려 생산성을 저하시키는 결과를 낳았다.

이로 인해 시간이 지나 결국 타입스크립트(TypeScript)가 탄생하였다. 프로그램 실행 전, 즉 런타임 이전에 미리 컴파일러가 코드의 오류 여부를 검사하는 것을 정적 검사(static check)라 하는데, 타입스크립트는 프로그램 실행 전 미리 타입에 관한 오류 여부를 검사해주는 정적 타입 검사(static type check)를 지원하는 언어이다.

조금 특이한 점은 Java, Python 등 기존의 언어들은 각자의 언어 체계, 문법 등이 독립적으로 존재하는 반면, 타입스크립트는 타입에 관한 개념만 추가된 것일 뿐, 기본적으로는 순수 자바스크립트의 확장 선상에 있다는 점이다. 즉, 개발자 입장에서는 기존에 쓰던 자바스크립트 문법대로 그대로 코드를 작성하고, 타입이 필요할 때 타입스크립트의 기능을 가져와 그 위에 올려 쓸 수 있다는 것이다. 이로 인해 “Typescript는 Javascript의 상위 집합(superset)이다.”라는 말도 나왔다. 이로 인해, 다른 언어들과는 달리 타입스크립트는 자바스크립트 사용자 입장에서는 전혀 새로운 언어는 아니기에 상대적으로 학습 진입장벽이 그리 높지 않다고도 말할 수 있겠다. 그래서 사실 타입스크립트의 모든 내용들을 깊숙히까지 공부하기보다는 필요하다 느끼는 핵심 기능들만 학습해도 문제가 없을거라고 한다.

브라우저는 아직까지는 타입스크립트 코드를 해석할 능력이 없다고 한다. 그래서 타입스크립트로 작성된 코드는 반드시 순수 자바스크립트 언어로의 컴파일 과정이 포함되어야 한다. 이 과정에서, 타입스크립트에서 제공하는 문법으로 정의한 타입들은 모두 삭제되어 컴파일된다. 어쩌면 당연한 것이, 순수 자바스크립트 자체에는 타입과 관련된 문법이 없기에 컴파일 과정에서 타입스크립트 문법으로 작성된 코드는 사라질 수밖에 없다. 다시 말해, 타입스크립트는 기존의 자바스크립트 문법, 체계에 전혀 간섭하지 않으면서 정적 타입 기능을 지원한다는 것이다.

한 편, 보통은 인간이 이해할 수 있는 고수준(high-level) 언어에서 기계가 이해할 수 있는 바이트 코드나 기계어 등의 저수준 언어로 변환되는 과정을 “컴파일”이라 부르는데, 사실 컴파일이란 용어는 그것보다 더 큰 개념으로, 한 언어에서 다른 언어로 변환되는 것 자체를 컴파일이라 부른다고 한다. 어쨌거나 여기에는 타입스크립트에서 자바스크립트로 변환되는 과정도 “컴파일”이라 부를 수 있다.

다만 타입스크립트와 자바스크립트는 모두 인간이 이해할 수 있는 고수준 언어이다. 즉, 언어의 추상화 정도가 비슷한 언어들이다. 이렇게 서로 비슷한 수준의 언어끼리 변환되는 과정을 따로 “트랜스파일(Transpile)”이라고도 부른다(높은 버전의 자바스크립트 코드를 호환성을 위해 낮은 버전의 것으로 바꾸는 것도 여기에 해당된다고 한다). 사실 실제로는 타입스크립트 코드에서 자바스크립트 코드로 변환되는 과정을 컴파일이라고도, 트랜스파일이라고도 부르며 혼용하여 사용하는 것 같았다. 오히려 “컴파일”이란 용어를 더 많이 사용하는 것 같았다.

어쨌거나 이제 타입스크립트 덕분에 자바스크립트에서도 정적 타입의 특성을 그대로 적용할 수 있게 된다. 이러한 정적 타입 언어의 장점으로는 다음과 같이 정리할 수 있겠다. 이러한 장점들은 곧 타입스크립트의 장점이 된다.

  • 런타임 단계에서 오류를 뒤늦게 발견하고 수정하는 것에 비하면 컴파일 단계에서 미리 타입 관련 오류, 버그를 발견할 수 있다. 이는 곧 생산성 및 개발자 경험에도 영향을 끼친다.
  • 대규모 프로젝트 및 협업에서도 문제없이 개발할 수 있다. 다른 사람이 만든 함수의 인자로 어떤 타입의 데이터를 넣어야할지 분명하기에 불필요한 추가적인 의사소통이 필요없다. 이러한 정적 타입의 장점은 라이브러리 제작자 및 사용자에게도 유용하다.
  • 백엔드와 프론트엔드 간 데이터 통신에 유용하다. 백엔드 서버 측에서 JSON 형태의 데이터를 프론트엔드 측에 전송할 때 프론트 측에서 이에 관한 타입이 미리 정의되어 있다면 서버 측에서 전송하는 데이터 내 여러 속성들을 이해하기 쉬울 것이다.
  • IDE와 같이 사용하면 코드 자동 완성을 사용할 수 있다. 어떤 변수나 함수의 인자의 타입이 정해져 있다는 것은 그 타입에서 사용할 수 있는 메서드나 필드들을 미리 알 수 있다는 것이기에 개발자 입장에서는 개발이 더 편리해질 것이다.
  • 당연히 가독성, 유지보수에도 도움이 될 것이다. 코드를 작성한 자기 자신조차도 시간이 지나면 “이 코드가 뭐지”라며 단번에 코드를 이해하지 못할 때도 있다. 만약 이럴 때 타입조차 정의되어 있지 않다면 코드 이해에 어려움이 더해질 것이다.

타입스크립트 사용하기

이제 타입스크립트를 어떻게 사용하는지에 대해 살펴보겠다. 이미 Node.js 및 VSCode가 설치되어 있다고 가정하겠다. 여기서는 기본적인 타입스크립트 설치 및 사용법에 대해 살펴보겠다. 사실 이는 리액트에서의 타입스크립트 사용 방법과 다른 부분들이 있다. 필자가 한동안 사용할 Vite라는 빌드 툴을 사용하면 타입스크립트와 관련된 설정 파일들이 자동으로 설치되며, 심지어는 개발자가 직접 명령 프롬프트 창에 타입스크립트 관련 명령어를 치지 않아도 자동으로 컴파일되어 결과물이 눈에 보인다. 이에 관한 사항은 나중에 별도의 글에 작성하겠다.

설치

타입스크립트 코드에서 자바스크립트로 컴파일하기 위한 타입스크립트 컴파일러(TypeScript Compiler, tsc)가 존재하기에 이를 사용하기 위한 패키지를 설치해줘야 한다. 타입스크립트에는 컴파일 시점에서만 필요하기에 개발 의존성(dev dependency)으로 설치해야 한다. 이를 위해 옵션 명령어인 -D 를 추가하여 다음과 같이 명령어를 입력한다.

npm i -D typescript

코드 2-1.

사실 내 컴퓨터 내 어디서든 타입스크립트를 사용하고자 한다면 대신 -g 옵션을 사용하여 설치할 수 있다. 그러면 이후에 다른 곳에서 타입스크립트를 사용하기 위해 또 별도의 명령어를 칠 필요가 없다.

npm i -g typescript

코드 2-2.

위 명령어를 통해 결과적으로 타입스크립트 컴파일러를 사용할 수 있게 된다. 이제 tsc 라는 명령어를 쓸 수 있게 된다. 다음은 현재 내 컴퓨터에 설치된 타입스크립트 컴파일러(tsc)의 버전을 확인할 수 있는 명령어이다.

npx tsc -v

코드 2-3.

타입스크립트 파일 생성, 코드 작성, 컴파일

이번에는 간단하게 타입스크립트 코드를 작성해보겠다. 타입스크립트 파일 확장자는 .ts 이므로 이에 유념하며 타입스크립트 파일을 생성한다. 필자는 basic.ts 라는 파일을 생성했으며 다음과 같이 코드를 작성해보았다.

interface Person {
  firstName: string;
  lastName: string;
}

const greeter = (person: Person): string => {
  return `hello, ${person.firstName} ${person.lastName}`;
};

let user: Person = { firstName: 'kim', lastName: 'quel'};

console.log(greeter(user));

코드 3-1. basic.ts

이 코드를 자바스크립트로 컴파일하려면 명령 프롬프트 창에서 위 파일과 같은 위치에 있는 상태에서 다음과 같은 명령어를 입력하면 된다.

npx tsc basic.ts

코드 3-2. tsc 명령어

그러면 같은 위치에 basic.js 라는 자바스크립트 파일이 컴파일되어 나올 것이다.

var greeter = function (person) {
    return "hello, ".concat(person.firstName, " ").concat(person.lastName);
};
var user = { firstName: 'kim', lastName: 'quel' };
console.log(greeter(user));

코드 3-3. 컴파일된 basic.js

그런데 컴파일된 자바스크립트 코드에 var 등 오래된 문법이 보인다. 만약 이를 원치 않고 es6 방식으로 컴파일 되기 원한다면 --target es6 명령어를 추가하여 컴파일해야한다.

npx tsc --target es6 basic.ts

코드 3-4.

const greeter = (person) => {
    return `hello, ${person.firstName} ${person.lastName}`;
};
let user = { firstName: 'kim', lastName: 'quel' };
console.log(greeter(user));

코드 3-5. es6 문법으로 컴파일된 basic.js

한 편, 타입스크립트로부터 컴파일된 자바스크립트 코드는 기본적으로 CommonJS라는 모듈 시스템이 적용되어 있다고 한다. 만약 ESM 모듈 시스템으로 컴파일하고자 한다면 --module es6 명령어를 입력한다.

npx tsc --module es6 (타입스크립트 파일명)

코드 3-6.

설정 파일: tsconfig.json

그런데 위와 같은 옵션 명령어들을 일일이 치는 것은 매우 번거로울 것이다. 이를 따로 설정 파일에 작성해두면 더 좋을 것이다.

타입스크립트에서는 이러한 타입스크립트 관련 설정을 할 수 있는 tsconfig.json 파일이라는 것이 존재한다. 프로젝트 루트 폴더에 해당 파일을 생성한다. 앞서 살펴본 옵션들을 자동으로 적용하게끔 한다면 다음과 같이 작성한다.

{
  "compilerOptions": {
    "target": "ES6",
    "module": "ES6"
  }
}

코드 4-1. tsconfig.json

그러면 npx tsc 라고만 치면 해당 프로젝트 내 모든 ts 파일들이 es6 문법과 ESM 모듈 시스템으로 컴파일될 것이다.

그리고 tsconfig.json에는 이 외에도 여러가지 설정들을 할 수 있으니 필요하면 검색하여 찾아보는 것을 권장한다.

글을 마치며…

이 글에서는 백엔드 개발자를 희망하는 나로서 타입스크립트를 접할 수밖에 없었던 이유를 서술하며, 타입스크립트란 무엇인지 등장 배경과 함께 서술하며 관련 개념들도 같이 설명하였다. 그리고 타입스크립트를 설치하고 컴파일하여 사용하는 방법에 대해서도 간단히 살펴보았다.

다음에는 타입스크립트와 관련하여 대략 다음과 같은 순서대로 나눠 글을 작성하고자 한다.

  • 타입스크립트 기초 및 핵심 개념, 문법들
  • 리액트에서 타입스크립트 사용하기

앞서 언급했듯, 필자는 타입스크립트를 말 그대로 리액트에서 정적 타입으로 사용하기 위한 용도로 생각하고 있어서 타입스크립트에 대해 그리 깊숙히 공부하지는 않고, 추가적인 개념들은 필요할 때마다 나중에 찾아보는 방식으로 접근하겠다고 하였다. 그래서 다음에 작성할 관련 글들에서도 몇몇 개념들이 다소 생략될 수 있다.


References

[1] TypeScript 공식 사이트

JavaScript With Syntax For Types.

[2] 타입스크립트 개요

Typescript는 어떻게 공부해야 하나요?

[3] 공식 TypeScript handbook 한글 문서

TypeScript 한글 문서

[4] Typescript handbook 핸드북

타입스크립트 핸드북

[5] 리액트 공식 문서 - 리액트에서의 TypeScript 사용하기

TypeScript 사용하기 – React

[6] React TypeScript Cheatsheets

React TypeScript Cheatsheets | React TypeScript Cheatsheets

[7] Transpile(트랜스파일)

🖥️ 컴파일 / 트랜스파일 / 인터프리터 비교 쉽게 설명

[8] 타입스크립트 컴파일러 사용법 (tsc 커맨드)

[9] 코딩에 진심인 사람을 위해 준비한 리액트 타입스크립트 | 실제 회사에서 쓰는 레벨 ver

[10] TypeScript: keyof 키워드

📘 객체를 타입으로 변환 - keyof / typeof 사용법

[11] 리액트에 타입스크립트 적용

8장. 리액트 프로젝트에서 타입스크립트 사용하기 · GitBook

[12] d.ts 파일에 대한 정보

[TypeScript] .d.ts파일이 뭘까?

[13] d.ts 파일에 대한 정보

타입 정의(d.ts) 파일이 뭔가요? | 코드잇

[14] d.ts 파일에 대한 정보

https://blog.naver.com/designerkhs/223656108804?trackingCode=rss)

[15] d.ts VS .ts

Don’t put your types in .d.ts files

This content is licensed under CC BY-NC 4.0

댓글남기기