2019년 11월 5일 3.7
이 정식버전으로 릴리즈되었습니다. 아래에선 3.7
에 추가된 주요기능들을 살펴보실 수 있어요! (rc버전에서 작성되었던 내용이지만 설명드린 내용들은 정식버전과 차이가 없어 내용은 수정되지 않았습니다)
해당 포스트는 MicroSoft devblog에 Daniel Rosenwasser님이 기재하신 "Announcing TypeScript 3.7 RC (링크)"를 의역 및 요약해 작성되었습니다. 자세한 내용이 알고 싶으시다면, 해당 포스트보단 링크를 통해 확인해주세요.
작성일 기준이기 때문에 포스트보단 사용하시는 IDE나 라이브러리의 이슈등을 확인하시는게 더 정확합니다.
Ctrl + Shift + P
(맥은 Command + Shift + P
)를 누르시고, "Typescript"를 입력하시어 Typescript: Select Typescript Version...
이라는 옵션을 통해 현재 워크스페이스의 버전이 업그레이드한 버전과 일치하는지 확인해주세요.1.19.1
버전이 릴리즈되어 prettier의 Typescript 3.7
버전 지원이 시작되었습니다.@typescript-eslint/parser
, @typescript-eslint/eslint-plugin
은 2.7.0
버전을 기준으로 사용하시면 안정적으로 Typescript 3.7
버전에 대한 지원을 받을 수 있습니다.Kotlin이나 Swift등의 언어를 사용해보신 분이라면 익숙하실 문법으로, 기존 자바스크립트에선 정식문법으로 채택되지는 않아 @babel/plugin-proposal-optional-chaining
라는 바벨플러그인을 통해 Optional Chaining문법을 사용할 수 있었습니다. 하지만 타입스크립트는 이를 지원하지 않아 코드가 길어지는 불편함이 있었는데요.
이번 3.7버전을 통해 타입스크립트에서도 Optional Chaining을 지원한다고 합니다.
Optional Chaining : 포스트를 작성하는 현재 TC39 Stage3 에 속해있는 문법입니다.
포스트를 읽고 계신 지금Optional Chaining
이 어디 속해있는지 궁금하시다면 여기를 클릭해주세요
서버로부터 유저 정보를 받고 싶은 상황을 가정해볼게요.
서버가 응답을 잘해서 데이터를 받았다면 data
라는 오브젝트에 user: { name: 'kim' }
를 받아올 예정입니다. 하지만 data
는 서버나 혹은 클라이언트의 네트워크 상태등 다양한 조건에 의해undefined
일 수도 null
일 수도 있다고 가정합시다.
위의 조건을 알고 data.user.name
를 받게되었을 때, 우리는 다음과 같은 코드를 작성하게 됩니다.
let username = (data === null || data === undefined) ?
undefined :
data.user.name();
물론 위의 코드처럼 길지 않게 if
나 삼항 조건 연산자(Conditional operator)
혹은 &&
를 이용할수도 있겠죠? 하지만 user
도 null
이나 undefined
일 수 있다면? 코드길이나 복잡도는 계속 올라갈겁니다. 보는 개발자가 힘들어지는 것이죠.
Optional Chaining 문법은 위의 코드를 다음과 같이 사용할 수 있게 만들어 줍니다.
let x = data?.user.name();
user
가 null
이나 undefined
일 수 있다면?
let x = data?.user?.name();
코드가 훨씬 간단해졌죠?
?.
연산자는 좌측의 값에 대해 null
인지 undefined
인지 확인하고 해당한다면 이후 속성을 찾는 작업은 중지하고 undefined
를 반환합니다.
&&
와의 차이점?.
연산자는 기존 코드에서 많이 사용된 &&
를 대체할 수 있겠지만 둘은 엄밀히 체크하는 타입이 다릅니다.
&&
연산자는 앞의 피연산자가 falsy(false, null, undefined, '', 0, NaN)
인지 확인하지만 ?.
연산자는 null
과 undefined
만을 확인합니다.
function getFirstElement<T>(arr: T[]) {
return arr?.[0]
}
위와 같이 arr
은 Optional이지만 간단하게 내부 요소에 접근하는 코드를 작성할 수 있습니다.
함수에 대해서도 함수가 있는지 없는지에 따라 실행 혹은 undefined
반환하는 용도로 사용할 수 있습니다.
function makeLog(log?:(message: string) => void) {
return log?.('log가 null이나 undefined가 아니라면 실행될 거예요!')
}
Nullish Coalescing Operator(이하 NCO)역시 현재 TC39 Stage3에 속해있는 문법입니다.
이 역시 JS에선 babel플러그인인 @babel/plugin-proposal-nullish-coalescing-operator
적용을 통해 사용할 수 있었는데요. 마찬가지로 이번 Typescript 3.7에 포함될 예정입니다.
NCO도 Optional Chaining과 마찬가지로 ??
라는 연산자를 통해 앞의 피연산자가 null
혹은 undefined
인지 확인하며,
그 쓰임은 ||
와 같습니다.
||
와의 차이점이미 ||
가 있는데 왜 굳이 ??
라는 연산자를 추가한 걸까요?
그 이유는 다음에서 확인할 수 있습니다.
const zero = 0;
const one = 1;
const anyNumber = zero || one; // 1
const anyNumberWithNCO = zero ?? one; // 0
이전의 타입스크립트에서 anyNumber
를 사용하는 목적이 아무 숫자나 받길 원하는 변수였다면, ||
를 사용해 해결할 수 없었습니다. ||
연산자는 falsy
값을 확인하기 때문에 anyNumber
의 값은 1
이 되었기 때문이죠. 이러한 문제들을 보다 간단한 문법을 통해 해결하기 위해 NCO는 도입되었습니다.
재귀적으로 참조하게 되는 경우에 있어 Type Alias는 태생적으로 제약이 있을 수 밖에 없습니다.
제약없이 작성된 다음과 같은 코드는 당연히 컴파일러에 의해 거부될겁니다.
type Foo = Foo;
하지만 3.6이전의 버전에서 몇몇 순환 Type Alias는 문제가 없음에도 불구하고 Error를 발생시켰습니다.
type ValueOrArray<T> = T | Array<ValueOrArray<T>>;
// ~~~~~~~~~~~~
// error: Type alias 'ValueOrArray' circularly references itself.
따라서 다음과 같이 interface
를 이용해 사용해야만 했습니다.
type ValueOrArray<T> = T | ArrayOfValueOrArray<T>;
interface ArrayOfValueOrArray<T> extends Array<ValueOrArray<T>> {}
하지만 3.7에선 위의 타입선언이 허용됩니다.
JSON을 타입지정하는 예시로 어떻게 타입선언이 변경되는지 확인해볼까요?
type Json =
| string
| number
| boolean
| null
| JsonObject
| JsonArray;
interface JsonObject {
[property: string]: Json;
}
interface JsonArray extends Array<Json> {}
type Json =
| string
| number
| boolean
| null
| { [property: string]: Json }
| Json[];
앞으론 호출하지 않는 함수에 대해서 강력하게 검사합니다. 설명으로는 감이 안오실 수 있으니 코드를 살펴보죠.
interface User {
isAdmin(): boolean;
}
function doAdminThing(user: User) {
// 언제나 true를 반환
if (user.isAdmin) {
return 'hello'
}
}
이경우 user.isAdmin을 통해 체크하는 if문은 항상 true를 반환하겠죠. 이전의 typescript는 이를 체크하지 않았지만 이젠 이런식으로 호출하지 않는 함수에 대해서 에러를 표시합니다.
다음과 같은 경우는 에러를 표시하지 않습니다.
interface User {
notify(): void;
doNotDisturb?(): boolean;
}
function issueNotification(user: User) {
// 1. 함수가 Optional인 경우
if (user.doNotDisturb) { ... }
// 2. 함수가 있는지 체크하고 함수를 호출한 경우
if (user.notify) user.notify();
}
만약 user.isAdmin
이 있는 함수인지 알고싶었다고 한다면? user.isAdmin
타입 정의시에 null
혹은 undefined
를 포함해 정의하거나 !!user.isAdmin
을 사용하면 됩니다.
앞서 소개드린 내용 외에도 Node.js의 assert
모듈과 같은 기능을 하기 위해 추가된 asserts
를 통해 assertion function을 작성할 수 있게 되었고,
Javascript파일에서만 사용되던 // @ts-nocheck
주석을 Typescript에서도 사용할 수 있게 되는 등의 크고작은 추가들 역시 있을 예정입니다.
보다 자세하게 알고 싶으시다면 포스트 하단 Reference를 참조해주세요
해당 포스트는 현재(2019.11.01 기준) rc버전에 대해서 포스팅하며, 정식 Release에선 바뀔 수 있다는 점을 말씀드립니다.
(시간이 된다면 릴리즈 후에 수정하도록 하겠습니다.)
Reference
오탈자 및 잘못된 내용에 대해선 댓글로 알려주시면 반영하도록 하겠습니다.
감사합니다 😀
이런글 너무 좋아요🤗
Graphql 쓸때 너무 좋을 것 같네요 ㅎㅎ