Skip to content

타입스크립트에서 동적·정적 타입 사용하기

이 글에서는 유니온 타입, 조건부 타입, 템플릿 리터럴 타입 그리고 제너릭과 같은 타입스크립트의 몇가지 심화된 형태를 살펴봅니다. 우리는 버그가 발생하기 전에 버그를 잡을 수 있도록 자바스크립트의 동작이 일정한 형식을 갖추기를 바랍니다. 이 글에서는 스매싱 매거진에서 2020년 말에 간행한 《TypeScript in 50 Lessons》의 모든 챕터에서 알려주는 몇 가지를 적용해보려고 합니다. 더 알아보고 싶다면 해당 내용을 꼭 확인해보세요!

자바스크립트는 본래 동적인 언어입니다. 우리는 개발자로서 적은 비용으로 많은 것을 보여줄 수 있고, 프로그래밍 언어와 언어의 런타임 환경이 우리가 정말 실행시키려는 것이 무엇인지 해석해줍니다. 이 점이 자바스크립트가 초심자들에게 인기 있는 이유이고, 숙련된 개발자들을 더 생산적으로 만들어주는 지점입니다. 그런데 여기서 주의할 점도 있습니다: 실수, 오타, 정확한 프로그램의 동작에 주의를 기울여야 합니다. 이는 우리 머릿속에서 많이 일어나는 일들입니다!

아래 예시를 살펴봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/qBqPqNN’>qBqPqNN</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

위 예시에는 라우트(또는 path)를 정의하는 https://expressjs.com/ 스타일의 서버가 있고, URL 로 요청이 오면 콜백이 실행됩니다.

콜백은 두 개의 인자를 받습니다.

  1. request 객체. 여기서 우리는 (GET, POST, PUT, DELETE 와 같은) HTTP method에 대한 정보를 얻고, 추가적인 매개변수들이 들어옵니다. 이 예시에서는 유저의 ID를 담고 있는 값이 userID 파라미터로 지정되어야 합니다.
  2. response 또는 reply 객체. 여기에서는 서버로부터 와서 클라이언트에 보내는 응답을 준비합니다. 적절한 상태코드(메서드 상태코드 status)와 JSON 결괏값을 전달합니다.

해당 예시에서는 과하게 단순화되어 있는 형태지만 우리가 하려는 것을 잘 보여줍니다. 위 코드에서는 에러가 많이 발생합니다. , 살펴봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/xxRXREV’>xxRXREV</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

놀랍군요, 실행 코드 세 줄과 세 개의 에러라니! 무슨 일일까요?

  1. 첫 번째 에러는 미묘합니다. (app.get 으로) GET 요청을 보내려고 하는 것을 app에 전달하는데 요청 메서드가 POST일 때만 무언가를 할 수 있게 되어 있습니다. 애플리케이션의 이 지점에서 method는 POST가 될 수 없습니다. 그래서 어떠한 응답도 하지 않게 되고, 이러한 상태는 예상치 못한 타임아웃을 야기할 수 있습니다.
  2. 상태 코드를 정확하게 보내는 것이 좋습니다. 그런데 20은 유효한 상태코드가 아닙니다. 클라이언트는 여기에서 어떤 일이 벌어지는지 이해하지 못할 수도 있습니다.
  3. 이 메시지는 되돌려 보내야 할 응답 메시지입니다. 파싱된 인자들에 접근할 수는 있지만 여기엔 미묘한 오타가 있습니다. userID이지 userId가 아닙니다. 모든 유저는 다른 곳에서 많이 본 것처럼 “Welcome, user undefined!”라는 문구를 보게 될 것입니다.

그리고 특히 자바스크립트에서 그런 것들이 발생합니다. 우리는 어떤 표현력을 –타입types으로 인해 한 번 신경 써야 했던 것이 아니라–늘릴 수 있지만 우리가 무엇을 하고 있는지 가까이에서 관심을 기울여야 합니다.

여기가 동적 프로그래밍 언어에 익숙하지 않은 사람들이 자바스크립트를 사용하는 데 반발심을 일으키는 지점입니다. 이런 사람들은 종종 발생 가능한 문제들을 가려내고, 에러를 미리 잡는 데 컴파일러를 이용합니다. 모든 것이 잘 돌아가게 하기 위해서 어떤 일을 더 해야 할지 당신이 머릿속으로 생각해야 하는 동안 그 추가될 업무의 양을 보고 그들은 눈살을 찌푸리며 거들먹거릴지도 모릅니다. 그들은 심지어 여러분에게 “자바스크립트는 타입이 없어요”라고 말할지도 모릅니다. 그것은 사실이 아닙니다.

타입스크립트의 선두적 설계자 아네르스 하일스베르Anders HejlsbergMS Build 2017 발표 에서 “자바스크립트에 타입시스템이 없는 것은 아닙니다. 단지 타입시스템을 공식화한 방법이 없는 것뿐입니다”라고 말했습니다.

이 점이 ‘타입스크립트TypeScript‘의 주요 목적입니다. 타입스크립트는 여러분의 자바스크립트 코드를 여러분이 알고 있는 것보다 더 잘 전달하고자 합니다. 타입 정보를 제공하면서 여러분이 무엇을 의도했는지 모호한 곳에서 의도를 잘 전달할 수 있도록 돕습니다.

 

기본 타입

이것이 지금 우리가 하려는 것입니다. Express 스타일의 서버에서 get 메서드를 가져와서 가능한 한 많은 에러를 검출할 수 있도록 타입 정보를 추가해봅시다.

기본 타입을 적는 것부터 시작합니다. get 함수를 가리키는 app 객체가 있습니다. get 함수는 string 타입의 path와 콜백을 취합니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/QWGqGKz’>QWGqGKz</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

string은 원시 타입으로 불리는 기본 타입인 반면, CallbackFn은 우리가 분명하게 정의해야 하는 복합 타입입니다.

CallbackFn은 두 개의 매개인자가 있는 함수 타입입니다.

  • Req, ServerRequest 타입
  • reply, ServerReply 타입

CallbackFnvoid(반환하는 값이 없을 때의 반환 값 타입-옮긴이)를 리턴합니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/RwoLooL’>RwoLooL</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

ServerRequest는 대부분의 프레임워크에서 다소 복잡한 객체입니다. 여기서는 설명을 위해 단순화해서 사용하고 있습니다. “GET” “POST” “PUT” “DELETE” 등 요청을 위해 메서드로 문자열을 넘깁니다. 이 메서드는 매개인자로 레코드를 넘깁니다. 레코드는 키keys와 값values 형태로 이루어진 객체입니다. 잠시 모든 string 프로퍼티가 string 키에 할당될 수 있다고 해봅시다. 이 부분은 후에 리팩토링해볼 것입니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/GRNMNNy’>GRNMNNy</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

서버응답을 위해 몇 개의 함수를 배치하는데, 이 함수들은 더 많은 데이터를 가지고 있는 진짜  ServerReply에 대한 정보를 알고 있습니다. send 함수는 우리가 보내려는 데이터를 선택적 매개인자(아래 코드상 send: (obj?: any)의 obj 부분-옮긴이)로 지닐 수 있습니다. 그리고 status 함수로 상태 코드를 받을 수 있게 됩니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/WNoZooY’>WNoZooY</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

벌써 우리는 무언가 하나를 해냈고, 몇 가지 에러 발생 가능성을 줄였습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/oNYGYBB’>oNYGYBB</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

하지만 여전히 잘못된 상태코드(현재는 어떤 숫자든 가능합니다)를 보낼 수 있고, HTTP 메서드(어떤 문자열이든 가능합니다) 중에서 어떤 게 가능한지 알 수 없습니다. 타입을 조금 더 다듬어봅시다.

 

더 작은 단위의 조합

원시타입은 특정 카테고리에 해당하는 모든 값의 집합으로 볼 수 있습니다. 예를 들어, string은 자바스크립트로 표현할 수 있는 모든 문자열을 포함하고, number는 부동 소수점을 포함한 모든 숫자를 포함합니다. booleantruefalse 같은 모든 Boolean 값들을 포함합니다.

타입스크립트는 더 작은 단위의 하위 집합들도 가능하게 합니다. 예를 들어, 우리는 Method라는 타입을 만들 수 있고, 이 Method 타입은 우리가 받을 수 있는 모든 HTTP 메서드를 문자열로 포함하고 있습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/wvorogx’>wvorogx</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

Method는 더 큰 단위의 문자열 집합의 부분집합입니다. Method는 리터럴 타입으로 된 유니온 타입입니다. 주어진 집합(Methods-옮긴이)의 가장 작은 단위, 리터럴 문자열, 리터럴 숫자. 여기에 모호한 것은 없습니다. “GET”은 말 그대로 “GET”일 뿐입니다. 어떤 크기의 타입이든 이를 작은 단위의 부분 집합으로 만들면서 유니온 타입을 만들게 됩니다. 리터럴 타입을 조합하거나 유니온으로 지정할 수 있는 방법들은 많습니다.

서버에서 콜백이 실행될 때 즉각적으로 반영됩니다. 이제는 위와 같은 네 개의 메서드들(또는 필요에 따라 더 많은 메서드들)을 구분하여 사용할 수 있고, 코드 내에서 모든 가능성을 열어둘 수 있습니다. 타입스크립트가 가이드해줍니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/ZEBXBez’>ZEBXBez</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

각각의 case 문으로 타입스크립트는 사용 가능한 옵션들을 제공해줍니다. 여기에서 직접 실행해보세요. 옵션들을 모두 사용하면, 이 경우는 타입스크립트가 있을 수 없다고 default 브랜치(스위치 문의 디폴트 값-옮긴이)에서 말해줄 것입니다. 이것은 말 그대로 never 타입이고, 해결해야 하는 에러에 접근할 수 있다는 의미입니다.

이는 에러를 줄일 수 있는 한 예시입니다. 지금은 어떤 HTTP 메서드들을 사용할 수 있는지 정확하게 모릅니다.

StatusCode에 유효한 숫자들을 정의하면서 HTTP 상태 코드도 동일하게 적용해볼 수 있습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/zYoEoZv’>zYoEoZv</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

다시 말해서 타입 StatusCode는 유니온 타입입니다. 원활한 작동에 실패하는 코드를 볼 수 있듯이 유니온 타입이라는 정보와 함께 또 다른 에러들을 도출해냅니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/mdOBOWp’>mdOBOWp</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

소프트웨어는 더 안전해집니다! 그러나 우리는 조금 더 안전하게 할 수 있습니다.

 

제너릭 입문하기

app.get으로 라우팅 경로를 지정할 때, 우리는 HTTP 메서드 get만 사용할 수 있다는 것을 알고 있습니다. 하지만 타입 정의에서는 유니온 타입의 모든 가능한 범주를 확인해야 합니다.

HTTP의 모든 가능한 메서드들을 위한 콜백 함수를 정의한다면, CallbackFn이 적절할 것입니다. 하지만 우리가 app.get으로 호출하려고 한다면 타입 규칙에 맞출 수 있는 타입을 추가하는 것이 좋을 것입니다.

타입스크립트 제너릭TypeScript generics이 도움이 될 것입니다! 제너릭은 정적 타입을 바탕으로 동적 타이핑을 제어할 수 있도록 도와주는 타입스크립트의 주요 기능 중 하나입니다. TypeScript in 50 Lessons 마지막 세 장에서 모든 제너릭의 복잡한 특징과 독특한 기능들을 확인할 수 있습니다.

지금 알아야 하는 것은 SeverRequest를 다른 집합이 아니라 Methods 타입의 한 종류로 정의하고자 한다는 점입니다. 이를 위해, 함수를 이용해 매개변수를 정의할 수 있는 곳에서 제너릭 문법을 이용합니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/eYBGBWY’>eYBGBWY</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

아래와 같이 실행될 것입니다.

  1. ServerRequest는 꺾쇠 괄호를 사용하는 제너릭 타입으로 표현합니다.
  2. Met이라는 제너릭 매개변수를 정의하고, MetMethods의 부분집합입니다.
  3. 메서드를 정의하기 위해서 제너릭 매개변수를 제너릭 변수로 사용합니다.

여기에서 나의 또 다른 글 naming generic parameters를 추천하고 싶습니다.
이렇게 수정하면 우리는 서로 다른 ServerRequest들을 중복해서 규정하지 않고, 사용할 수 있습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/LYbzbyx’>LYbzbyx</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

ServerRequest의 인터페이스를 변경했기 때문에 CallbackFnget 함수처럼 ServerRequest가 사용하는 모든 다른 타입을 변경해야 합니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/bGBoBWm’>bGBoBWm</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

get 함수와 같이 제너릭 타입에 실제 매개인자를 넘깁니다. 이러한 형태는 단지 Methods의 부분이 아니고, 지금 다루고 있는 것이 해당하는 부분집합이라는 것을 알고 있습니다.
그래서 지금은 app.get을 사용하면 req.method를 위한 값만 지니게 됩니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/eYBGBRY’>eYBGBRY</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

이런 방식으로 app.get 콜백을 만들면 HTTP 메서드를 “POST”나 다른 비슷한 것들을 가정하지 않게 됩니다. 우리가 지정한 타입을 봅시다. 이 시점에 다루고 있는 것을 정확히 알 수 있습니다.

이미 request.method가 타입이 잘 짜여 있고, 각 기능의 실제 상태를 잘 반영한다는 것을 확인했습니다. 유니온 타입 Methods를 쪼개어 부분집합으로 만드는 것의 장점은 app.get 외의 일반적 목적의 콜백 함수를 타입 안정적으로(에러 없이 예측 가능한 결과를 내는 것) 만들어낼 수 있다는 점입니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/YzprpaE’>YzprpaE</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

 

타입 매개변수

아직 다루지 않은 것은 파라미터 객체의 타입을 작성하는 것입니다. 지금까지는 string 키에 직접 접근하도록 해왔습니다. 이 부분을 조금 더 명확하게 짚는 것이 지금 우리가 하려는 일입니다.

먼저 제너릭 변수를 하나 더 추가하고자 합니다. 하나는 methods 타입을 위한 것이고, 다른 하나는 Record에서 가능한 키 값들의 타입 정의를 위한 것입니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/dyOVORW’>dyOVORW</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

제너릭 타입 변수 Parstring 타입의 부분집합이 될 수 있고, 값이 주어지지 않았을 때 기본값도 각각 string 타입입니다. 이렇게 타입을 지정하면 ServerRequest에 우리가 기대하는 값을 알려줄 수 있습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/BaQwQZP’>BaQwQZP</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

get 함수에 새로운 매개인자를 추가하고 CallbackFn 타입을 지정합시다. 그러면 요청된 매개변수들을 설정할 수 있습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/zYoEodr’>zYoEodr</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

만약 Par 타입 변수를 명확히 지정하지 않으면 타입은 자연스럽게 Par의 디폴트 값으로 string을 지정한 대로 작동할 것입니다. 그렇지 않고 타입을 명확하게 지정한다면 req.params 객체에 알맞는 타입을 얻게 됩니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/VwmMmzz’>VwmMmzz</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

좋습니다! 여기서 한 가지 더 개선할 수 있는 부분이 있습니다. 여전히 모든 string 값을 app.getpath 인자로 넘길 수 있는 상태입니다. 여기에서도 Par 변수를 활용한 점을 반영하면 더 좋을 것 같습니다.

할 수 있습니다! Typescript 4.1 버전이 릴리즈되면서 템플릿 리터럴 타입을 생성할 수 있게 되었습니다. 문장 그대로 타입 레벨에서의 문자열 템플릿 리터럴입니다. 문자열 조합을 나누어 문자열 리터럴의 부분집합으로(Methods에서 했던 것처럼) 두면서, 템플릿 리터럴 타입은 우리가 모든 문자열 범주를 포함할 수 있게 합니다.
매개변수 앞에 콜론을 붙이는express 스타일에서 변수 Par가 적절하게 포함되는 곳에 IncludesRoutesParams라고 불리는 타입을 만들어봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/PobJbKa’>PobJbKa</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

제너릭 타입 IncludesRoutesParams은 string의 하위 집합인 한 개의 인자를 받습니다. 그것은 두 개의 template literals의 유니온 타입을 만들어냅니다.

  1. 첫 번째 template literal은 어떤 문자열로 시작하고, /가 포함되고, :와 매개변수 이름이 순서대로 뒤따릅니다. 매개변수는 route 문자열의 맨 마지막에 있다는 것을 알 수 있습니다.
  2. 두 번째 template literal은 어떤 문자열로 시작하고, /: 뒤에는 매개변수의 이름이 뒤따르는 패턴입니다. 그리고 /가 이어지는 문자열과 함께 하나 더 붙습니다. 이러한 유니온 타입의 변형 방법(branch)은 매개변수가 route 주소 내 어디에 있든 찾을 수 있게 합니다.

아래는 매개변수 userID인 가 서로 다른 테스트 케이스에서 어떻게 나타나는지 보여줍니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/rNWGWGV’>rNWGWGV</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

get 함수에 새로운 기능을 넣어봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/abBLBLZ’>abBLBLZ</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

좋습니다! 우리는 실제 라우팅 주소에 매개변수를 추가하는 것을 빠뜨리지 않게 할 수 있는 또 다른 안전한 타입시스템을 구축했습니다. 강력하지 않나요!

 

제너릭 바인딩

하지만 아직 만족스럽지 않습니다. 라우팅 주소가 조금 더 복잡해지는 몇 가지 경우가 있습니다

  1. 첫 번째 이슈는 제너릭 타입 매개변수를 지정할 때 파라미터 값을 분명하게 명시해야 한다는 것입니다. Par 변수를 함수의 path 인자로만 사용하고 싶더라도, Par 값을 “userID”로 지정해야 합니다. 이건 자바스크립트스러운 방법이 아닙니다.
  2. 이러한 접근은 하나의 라우팅 변수만 다룰 수 있습니다. 유니온을, 예를 들어 “userID | “orderId” 이렇게 추가하면 그중 하나만 매개변수로 사용할 수 있습니다. 그것이 집합이 작동하는 방식입니다. 그것은 하나가 될 수도 있고, 또 다른 것이 될 수도 있게 해줍니다.

분명히 더 좋은 방법이 있을 것입니다. 확실히 있습니다. 조금 어려운 이야기로 끝날지 모릅니다.

순서를 뒤집어봅시다. 제너릭 변수로 라우팅 변수를 지정하지 않고, 오히려 app.get의 첫 번째 인자로 넘기고 있는 path의 변수를 먼저 추출해봅시다.

실제 값을 얻기 위해 우리는 타입스크립트에서 제너릭 바인딩이 어떻게 이루어지는지 보아야 합니다. identity 함수로 예를 들어봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/OJbxbxw’>OJbxbxw</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

여러분이 본 함수 중 가장 재미없는 함수일지 모릅니다. 그러나 이 함수는 한 가지 지점을 완벽하게 설명합니다. identity는 인자를 하나 받고, 입력 값을 그대로 출력합니다. 타입은 제너릭 타입 T이고, 또 같은 타입을 출력하게 됩니다.

이제 Tstring으로 바인딩할 수 있습니다, 예를 들어

See the Pen <a href=’https://codepen.io/books-webactually/pen/MWbEbOg’>MWbEbOg</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

이렇게 명확하게 제너릭 바인딩을 하는 것은 우리가 문자열만 identity에 넘길 수 있게 하고, 그렇게 바인딩해두었기 때문에 출력 값의 타입도 string이 됩니다. 바인딩하는 것을 잊어버리면 흥미로운 일이 생깁니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/zYoEoPr’>zYoEoPr</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

이런 경우, 타입스크립트는 인자로 들어온 값의 타입을 추론하고, T를 string literal type(매개인자로 들어오는 문자열 값을 그대로 타입으로 취급하는-옮긴이) “yes”로 바인딩합니다. 이건 함수 매개인자를 literal type으로 바꾸는 훌륭한 방법입니다. 이 타입은 우리가 이후에 다른 제너릭 타입으로 사용합니다.

app.get에 적용하면서 살펴봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/oNYGYoW’>oNYGYoW</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

Par 제너릭 타입을 지우고, Path를 추가합니다. Path는 문자열에 속합니다. 제너릭 타입 변수인 Path에 실제값 path 를 지정하는 것은 get 함수에 매개변수를 넘길 때, 이 매개변수의 문자열 값 그대로 타입으로 받을 수 있다는 의미입니다. Path를 아직 만들어놓지 않은 새로운 제너릭 타입인 ParseRouteParams에도 넘깁니다.

ParseRouteParams를 만들어봅시다. 일단 이벤트들의 순서를 다시 바꿔봅시다. Path가 문제 없이 작동하도록 요청된 라우트 매개변수들을 제너릭에 넘기는 대신 라우트 주소를 넘기고, 가능한 라우트 변수들을 도출합니다. 이를 위해서 우리는 조건부 타입을 알아야 합니다.

 

조건부 타입과 재귀적 템플릿 리터럴 타입

조건부 타입은 단어 그대로 자바스크립트에 있는 세 개의 조건 연산자와 비슷합니다. 여러분은 조건을 확인하고, 조건이 맞으면 브랜치 A를 출력하고, 그렇지 않으면 브랜치 B를 출력합니다. 예를 들어

See the Pen <a href=’https://codepen.io/books-webactually/pen/PobJbOa’>PobJbOa</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

여기에서 우리는 Rte가 express 스타일(이전에 언급된 “/:”)로 끝나는 path를 포함하고 있는지 확인합니다. /:로 끝나는 Path를 포함하고 있다면 이 뒤에 이어지는 string을 추론합니다. path를 새로운 변수로 이끌어내는 것입니다. 이런 상황이 맞아떨어지면 새롭게 추출된 string을 도출하고, 그렇지 않으면 “라우팅 매개변수가 없습니다”라고 말하는 것처럼 never을 리턴하게 됩니다.
이렇게 시도하면 아래와 같은 결과를 얻게 됩니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/KKNXNyL’>KKNXNyL</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

좋습니다. 이전보다 훨씬 나아졌습니다. 이제 다른 모든 가능한 매개변수들을 알아내려고 합니다. 그러려면 또 다른 조건을 추가해야 합니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/eYBGByN’>eYBGByN</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

조건부 타입은 아래와 같이 작동합니다.

  1. 첫 번째 조건에서 라우트 내에 라우트 변수가 있는지 확인합니다. 있다면 라우트 변수와 뒤따르는 모든 값을 추출해냅니다 동일한 제너릭 타입을 재귀적으로 호출해 Rest라고 명명한 유니온 속에서 새롭게 발견된 라우트 파라미터 P를 리턴합니다. 예를 들어, 라우팅 주소 “/api/users/:userId/orders/:orderID”ParseRouteParams로 넘길 때 “userID”P로, “orders/:orderID”Rest로 추론해냅니다. 나머지 값들을 Rest 타입으로 똑같이 부를 수 있습니다.
  2. 이 부분이 두 번째 조건이 나오는 지점입니다. 마지막 부분에 타입이 있는지 여기에서 확인합니다. 이것이 “orders/:orderID”를 위한 경우입니다. “orderID”를 추출해내고 타입을 글자 그대로 리턴합니다.
  3. 라우트 매개변수가 더 남지 않으면, never를 리턴합니다.

Dan VanderkamParseRouteParams과 비슷한, 그리고 더 정교한 타입을 보여줍니다. 하지만 위에서 본 것 또한 잘 작동되는 방법입니다. 새롭게 적용된 ParseRouteParams을 사용해보면 아래와 같은 내용으로 보일 것입니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/qBqPqpr’>qBqPqpr</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

새로운 타입을 적용해보고, 아래와 같이 app.get이 최종적으로 적용된 형태를 확인해봅시다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/RwoLoxQ’>RwoLoxQ</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

와! 이 코드는 맨 처음에 보았던 자바스크립트 코드처럼 보입니다.

 

동적인 동작을 위한 정적 타입

App.get의 함수를 위해 만든 타입은 발생 가능한 많은 에러들을 막아냅니다.

  1. res.status()로는 숫자로만 상태값을 내려보낼 수 있습니다.
  2. req.method는 가능한 네 가지 문자열 중 하나이고, app.get을 사용할 때는 “GET”만 해당된다는 것을 알게 됩니다.
  3. 라우팅 파라미터를 파싱할 수 있고, 콜백 함수에 어떤 오타도 없다는 것을 확인할 수 있습니다.

이 게시물의 첫 부분에 등장하는 예시를 보면, 아래와 같은 에러 메시지를 받을 수 있습니다.

See the Pen <a href=’https://codepen.io/books-webactually/pen/yLVzVvB’>yLVzVvB</a> by webactually (<a href=’https://codepen.io/books-webactually’>@books-webactually</a>) on <a href=’https://codepen.io’>CodePen</a>.

그리고 모든 게 코드를 실행하기 전에 일어납니다! Express 스타일 서버는 자바스크립트의 동적인 환경에 완벽한 예시가 됩니다. 호출하는 메서드와 첫 번째 인자로 보내는 문자열, 콜백 내부의 실행 변화에 따라. 또 다른 예시를 만들어보면 모든 타입이 전부 달라 보일 것입니다.

그러나 코드를 수정하는 동안 잘 정의된 타입과 함께 동적인 실행을 체크할 수 있습니다. 코드가 수행되는 런타임이 아니라 정적 타입으로 컴파일되는 중에 이 모든 것이 작동하는 것입니다!

이것이 타입스크립트의 힘입니다. 우리는 이제 자바스크립트의 동적인 수행을 타입에 맞추어 형식화하려는 정적인 타입 시스템을 잘 알고 있습니다. 우리가 만들어둔 예시를 실행해보려면 TypeScript playground을 방문해 조작해보세요.

 

 

도서 소개

 

 

 

 

 

매트 마키스의 《웹디자이너를 위한 자바스크립트

자바스크립트의 기본 문법과 핵심 원리를 알기 쉽게 설명하여 자바스크립트의 기초를 튼튼하게 해준다. 객체에 대한 상세한 설명부터 문법 규칙, 프로토타입 속성, 함수 사용법, 루프를 처리하는 방법, DOM의 개념과 기능에 이르기까지 다양한 예제를 통해 고급 기술이나 응용 프레임워크의 실행 코드 작성 방법을 알려준다. 스크립트 작성 중에도 수시로 변하는 자바스크립트의 특성 때문에 이해하기 힘들었던 동작과 오류를 알기 쉽게 설명해준다. 자바스크립트의 문장을 간결하고 명확한 문장으로 만들 수 있는 방법, 코드의 복잡함을 제거하면서도 새로운 기능을 추가할 수 있는 코드 작성 방법 등을 제시한다. 기초에 충실한 책으로 기본기가 부족한 디자이너나 개발자에게 훌륭한 가이드가 될 것이다.

저작권 정보이 글은 Smashing Magazine 기사를 번역한 것입니다. 저작권자의 정당한 허락을 받은 저작물로 한국어판 저작권은 웹액츄얼리에 있습니다. 웹액츄얼리의 서면 동의 없이 무단 전재, 복제를 금합니다. 원본은 Dynamic Static Typing In TypeScript에서 확인할 수 있습니다.
참여를 기다립니다!웹액츄얼리에서 웹디자인 관련 영문 번역자를 찾습니다. 웹 콘텐츠 번역에 관심 있는 분은 메일로 간략한 본인 소개와 번역 이력을 보내주시면 연락드리겠습니다.
books@webactually.com


맨위로