타입 힌팅 개요
GitLab 프로젝트의 프론트엔드 코드베이스는 현재 타입을 요구하거나 강제하지 않습니다. 타입 주석 추가는 선택 사항이며, 우리는 현재 JavaScript 코드베이스에서 어떤 타입 안전성도 강제하지 않습니다. 그러나 타입 주석은 코드베이스에 명확성을 추가하는 데 매우 유용할 수 있습니다. 특히 공유 유틸리티 코드에서 그렇습니다. 이 문서는 현재 타입 힌팅이 어떻게 작동하는지, 새로운 타입 주석을 추가하는 방법, 및 GitLab 프로젝트에서 타입 힌팅을 설정하는 방법을 다루고자 합니다.
JSDoc
JSDoc는 JavaScript 코드에서 타입을 문서화하고 설명하는 도구로, 특별히 형성된 주석을 사용합니다. JSDoc의 타입 용어는 상대적으로 제한적이지만, 많은 IDE들 에 의해 널리 지원됩니다.
예제
함수 설명하기
함수 타입을 설명하기 위해 @param
및 @returns
를 사용합니다:
/**
* 두 숫자를 더합니다.
* @param {number} a 첫 번째 숫자
* @param {number} b 두 번째 숫자
* @returns {number} 두 숫자의 합
*/
function add(a, b) {
return a + b;
}
선택적 매개변수
매개변수 이름 주위에 대괄호 []
를 사용하여 선택적임을 표시합니다. 기본값은 [name=value]
구문을 사용하여 제공할 수 있습니다:
/**
* 두 숫자를 더합니다.
* @param {number} value
* @param {number} [increment=1] 선택적 매개변수
* @returns {number} 두 숫자의 합
*/
function increment(a, b=1) {
return a + b;
}
객체 매개변수
객체를 허용하는 함수는 @param
이름에서 object.field
표기를 사용하여 타입을 지정할 수 있습니다:
/**
* 두 숫자를 더합니다.
* @param {object} config
* @param {string} config.path 경로
* @param {string} [config.anchor] 앵커
* @returns {string}
*/
function createUrl(config) {
if (config.anchor) {
return path + '#' + anchor;
}
return path;
}
즉시 값을 할당하지 않은 변수의 타입 주석 달기
도구와 IDE는 즉시 값을 받지 않는 값의 타입을 추론하기 어렵습니다. @type
(https://jsdoc.app/tags-type) 표기를 사용하여 이러한 변수에 타입을 할당할 수 있습니다:
/** @type {number} */
let value;
더 많은 문법 세부사항은 JSDoc 공식 웹사이트를 참조하세요.
JSDoc 사용 팁
기본 타입에 소문자 이름 사용하기
대문자 Boolean
과 소문자 boolean
모두 허용되지만, 대부분의 경우 원시값이나 객체가 필요할 때는 소문자 버전이 올바른 선택입니다: boolean
, number
, string
, symbol
, object
.
/**
* `text`를 변환합니다.
* @param {string} text - 변환할 텍스트
* @returns {string} 변환된 텍스트
*/
const gettext = (text) => locale.gettext(ensureSingleLine(text));
잘 알려진 타입 사용하기
HTMLDivElement
또는 Intl
과 같은 잘 알려진 타입은 사용 가능하며 직접 사용할 수 있습니다:
/** @type {HTMLDivElement} */
let element;
/**
* 현재 로케일에 대한 Intl.DateTimeFormat의 인스턴스를 생성합니다.
* @param {Intl.DateTimeFormatOptions} [formatOptions] - 사용 가능한 옵션에 대해서는 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat를 참조하세요.
* @returns {Intl.DateTimeFormat}
*/
const createDateTimeFormat = (formatOptions) =>
Intl.DateTimeFormat(getPreferredLocales(), formatOptions);
기존 유형 정의를 import('path/to/module')
를 통해 가져오기
여기 Vue Test Utils Wrapper 변수를 주석 처리하는 방법에 대한 예시가 있습니다. 이들은 즉시 정의되지 않습니다:
/** @type {import('helpers/vue_test_utils_helper').ExtendedWrapper} */
let wrapper;
// ...
wrapper = mountExtended(/* ... */);
/** @type {import('@vue/test-utils').Wrapper} */
let wrapper;
// ...
wrapper = shallowMount(/* ... */);
주의:
import()
는 네이티브 JSDoc 구문이 아닙니다, 하지만 많은 IDE와 도구에서 인식됩니다. 이 경우, 우리는 코드의 명확성을 높이고 IDE의 개발자 경험을 개선하는 것을 목표로 하고 있습니다.
JSDoc의 한계
위에서 언급했듯이, JSDoc은 제한된 어휘를 가지고 있습니다. 그리고 이를 사용하면 유형을 완전히 설명할 수 없습니다. 하지만 때때로 3rd 파티 라이브러리의 유형 정의를 사용하여 우리의 코드에 대한 유형 추론을 작동하게 할 수 있습니다. 다음은 그런 접근법의 예입니다:
- export const mountExtended = (...args) => extendedWrapper(mount(...args));
+ import { compose } from 'lodash/fp';
+ export const mountExtended = compose(extendedWrapper, mount);
여기서 우리는 compose
함수의 TypeScript 유형 정의를 사용하여 mountExtended
함수에 추론된 유형 정의를 추가하고 있습니다. 이 경우 mountExtended
인수는 mount
인수와 같은 유형이 됩니다. 그리고 반환 유형은 extendedWrapper
반환 유형과 동일합니다.
우리는 여전히 JSDoc 구문을 사용하여 함수에 설명을 추가할 수 있습니다. 예를 들어:
/** 컴포넌트를 마운트하고 이를 위한 확장된 래퍼를 반환합니다. */
export const mountExtended = compose(extendedWrapper, mount);
시스템 요구 사항
IDE와 도구에서 GitLab 코드베이스 및 3rd 파티 패키지의 유형 정의가 올바르게 표시되기 위해 설정이 필요할 수 있습니다.
VS Code 설정
VS Code IntelliSense가 작동하는 데 문제가 있는 경우, TS 서버가 사용할 수 있는 메모리 양을 늘려야 할 수 있습니다. 이를 위해 settings.json
파일에 다음을 추가하세요:
{
"typescript.tsserver.maxTsServerMemory": 8192,
"typescript.tsserver.nodePath": "node"
}
별칭
우리의 코드베이스는 여러 가져오기에 대해 많은 별칭을 사용합니다. 예를 들어, import Api from '~/api';
는 app/assets/javascripts/api.js
파일을 가져옵니다. 하지만 IDE는 그 별칭을 알지 못할 수 있으며, 따라서 Api
의 유형을 알지 못할 수 있습니다. 대부분의 IDE에서 이를 수정하려면 jsconfig.json
파일을 생성해야 합니다.
GitLab 프로젝트에는 웹팩 구성과 현재 환경 변수를 기반으로 jsconfig.json
파일을 생성할 수 있는 스크립트가 있습니다. jsconfig.json
파일을 생성 또는 업데이트하려면 — GitLab 프로젝트 루트에서 다음을 실행하세요:
node scripts/frontend/create_jsconfig.js
jsconfig.json
파일은 gitignore 목록에 추가되므로, 이를 생성하거나 변경해도 GitLab 프로젝트에서 Git 변경 사항이 발생하지 않습니다. 이는 Git 풀에도 포함되지 않으므로, 수동으로 생성하거나 업데이트해야 합니다.
3rd 파티 TypeScript 정의
점점 더 많은 라이브러리가 유형 정의를 위해 TypeScript를 사용하고 있지만, 일부는 여전히 JSDoc 주석이 달린 타입이나 아예 타입이 없을 수 있습니다. 이러한 갭을 메우기 위해 TypeScript 커뮤니티는 인기 있는 JavaScript 라이브러리의 독립형 유형 정의를 생성하고 지원하는 DefinitelyTyped 이니셔티브를 시작했습니다. 우리는 해당 유형 패키지를 명시적으로 설치(yarn add -D "@types/lodash"
)하거나, 일부 언어 서비스에서 제공되는 자동 유형 획득(ATA) 기능을 사용하여 이러한 정의를 사용할 수 있습니다.
자동 유형 획득(ATA)은 DefinitelyTyped 목록에서 유형 정의를 자동으로 가져옵니다. 하지만 ATA가 작동하려면 전 세계적으로 설치된 npm
이 필요할 수 있습니다. IDE는 npm
실행 파일의 위치를 설정하기 위한 대체 구성 옵션을 제공할 수 있습니다. 자세한 내용은 IDE 문서를 참조하세요.
ATA가 작동할 것이라는 보장은 없으며 Lodash는 우리의 유틸리티 함수의 많은 기반이므로 우리는 package.json
의 devDependencies
에 DefinitelyTyped definitions for Lodash를 명시적으로 추가했습니다. 이를 통해 모든 사용자가 기본적으로 lodash
기반 함수의 유형 힌트를 받도록 보장합니다.