타입 힌팅 개요
GitLab v19.1GitLab 프로젝트의 프론트엔드 코드베이스는 현재 타입을 필수로 요구하거나 강제하지 않습니다. JSDoc은 특별하게 형성된 주석을 사용하여 JavaScript 코드에서 타입을 문서화하고 설명하는 도구입니다. @param과 @returns를 사용하여 함수 타입을 설명합니다:
GitLab 프로젝트의 프론트엔드 코드베이스는 현재 타입을 필수로 요구하거나 강제하지 않습니다. 타입 어노테이션 추가는 선택 사항이며, 현재 JavaScript 코드베이스에서 타입 안전성을 강제하지 않습니다. 그러나 타입 어노테이션은 코드베이스의 명확성을 높이는 데 매우 도움이 될 수 있으며, 특히 공유 유틸리티 코드에서 유용합니다. 이 문서는 타입 힌팅이 현재 어떻게 동작하는지, 새로운 타입 어노테이션을 추가하는 방법, 그리고 GitLab 프로젝트에서 타입 힌팅을 설정하는 방법을 다룹니다.
JSDoc#
JSDoc은 특별하게 형성된 주석을 사용하여 JavaScript 코드에서 타입을 문서화하고 설명하는 도구입니다. JSDoc의 타입 어휘는 상대적으로 제한적이지만, 많은 IDE에서 널리 지원됩니다.
예시#
함수 설명#
@param과 @returns를 사용하여 함수 타입을 설명합니다:
/**
* Adds two numbers
* @param {number} a first number
* @param {number} b second number
* @returns {number} sum of two numbers
*/
function add(a, b) {
return a + b;
}
선택적 파라미터#
파라미터 이름 주위에 대괄호 []를 사용하여 선택적 파라미터로 표시합니다.
[name=value] 구문을 사용하여 기본값을 제공할 수 있습니다:
/**
* Adds two numbers
* @param {number} value
* @param {number} [increment=1] optional param
* @returns {number} sum of two numbers
*/
function increment(a, b=1) {
return a + b;
}
객체 파라미터#
객체를 받는 함수는 @param 이름에 object.field 표기법을 사용하여 타입을 지정할 수 있습니다:
/**
* Adds two numbers
* @param {object} config
* @param {string} config.path path
* @param {string} [config.anchor] anchor
* @returns {string}
*/
function createUrl(config) {
if (config.anchor) {
return path + '#' + anchor;
}
return path;
}
즉시 값이 할당되지 않는 변수의 타입 어노테이션#
도구와 IDE는 즉시 값을 받지 않는 변수의 타입을 추론하기 어렵습니다.
@type 표기법을 사용하여 이러한 변수에 타입을 할당할 수 있습니다:
/** @type {number} */
let value;
더 많은 구문 세부 사항은 JSDoc 공식 웹사이트를 참조하세요.
JSDoc 사용 팁#
기본 타입에는 소문자 이름 사용#
대문자와 소문자 모두 허용되지만, 대부분의 경우 기본 타입이나 객체에는 소문자를 사용합니다:
boolean, number, string, symbol, 또는 object.
/**
* Translates `text`.
* @param {string} text - The text to be translated
* @returns {string} The translated text
*/
const gettext = (text) => locale.gettext(ensureSingleLine(text));
잘 알려진 타입 사용#
HTMLDivElement나 Intl과 같은 잘 알려진 타입은 사용 가능하며 직접 사용할 수 있습니다:
/** @type {HTMLDivElement} */
let element;
/**
* Creates an instance of Intl.DateTimeFormat for the current locale.
* @param {Intl.DateTimeFormatOptions} [formatOptions] - for available options, please see 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에서의 개발자 경험(Developer Experience)을 향상시키는 것을 목표로 합니다.
JSDoc의 한계#
앞서 언급한 바와 같이 JSDoc은 제한적인 어휘를 가지고 있습니다. 그리고 이를 사용하면 타입을 완전히 설명하지 못할 수 있습니다. 그러나 경우에 따라 서드파티 라이브러리의 타입 정의를 사용하여 코드에 타입 추론이 동작하도록 만들 수 있습니다. 다음은 그러한 접근 방식의 예시입니다:
- export const mountExtended = (...args) => extendedWrapper(mount(...args));
+ import { flowRight } from 'lodash-es';
+ export const mountExtended = flowRight(extendedWrapper, mount);
여기서 flowRight 함수의 TypeScript 타입 정의를 사용하여 mountExtended 함수에 추론된 타입 정의를 추가합니다.
이 경우 mountExtended의 인수는 mount의 인수와 동일한 타입이 됩니다.
그리고 반환 타입은 extendedWrapper의 반환 타입과 동일합니다.
함수에 설명을 추가하기 위해 JSDoc 구문을 계속 사용할 수 있습니다. 예를 들면:
/** Mounts a component and returns an extended wrapper for it */
export const mountExtended = flowRight(extendedWrapper, mount);
시스템 요구 사항#
GitLab 코드베이스와 서드파티 패키지의 타입 정의가 IDE 및 도구에서 올바르게 표시되려면 설정이 필요할 수 있습니다.
VS Code 설정#
VS Code IntelliSense 동작에 문제가 있는 경우 TS 서버가 사용할 수 있는 메모리 양을 늘려야 할 수 있습니다.
이를 위해 settings.json 파일에 다음을 추가하세요:
{
"typescript.tsserver.maxTsServerMemory": 8192,
"typescript.tsserver.nodePath": "node"
}
별칭(Aliases)#
코드베이스는 임포트에 많은 별칭을 사용합니다.
예를 들어, import Api from '~/api';는 app/assets/javascripts/api.js 파일을 가져옵니다.
그러나 IDE는 해당 별칭을 알지 못할 수 있으므로 Api의 타입을 알지 못할 수 있습니다.
대부분의 IDE에서 이 문제를 해결하려면 jsconfig.json 파일을 생성해야 합니다.
GitLab 프로젝트에는 webpack 구성과 현재 환경 변수를 기반으로 jsconfig.json 파일을 생성할 수 있는 스크립트가 있습니다.
jsconfig.json 파일을 생성하거나 업데이트하려면 GitLab 프로젝트 루트에서 다음을 실행하세요:
node scripts/frontend/create_jsconfig.js
jsconfig.json은 gitignore 목록에 추가되어 있으므로, 이를 생성하거나 변경해도 GitLab 프로젝트에서 Git 변경 사항이 발생하지 않습니다.
이는 또한 Git 풀에 포함되지 않는다는 의미이므로, 수동으로 생성하거나 업데이트해야 합니다.
서드파티 TypeScript 정의#
점점 더 많은 라이브러리가 타입 정의에 TypeScript를 사용하고 있지만, 일부는 여전히 JSDoc으로 어노테이션된 타입을 갖거나 타입이 전혀 없을 수 있습니다.
이 격차를 해소하기 위해 TypeScript 커뮤니티는 인기 있는 JavaScript 라이브러리에 대한 독립적인 타입 정의를 생성하고 지원하는 DefinitelyTyped 이니셔티브를 시작했습니다.
타입 패키지를 명시적으로 설치하거나(yarn add -D "@types/lodash"), 일부 Language Service에서 사용 가능한 자동 타입 획득(Automatic Type Acquisition, ATA)이라는 기능을 사용하여 해당 정의를 사용할 수 있습니다
(예: VS Code의 ATA).
자동 타입 획득(ATA)은 DefinitelyTyped 목록에서 타입 정의를 자동으로 가져옵니다.
그러나 ATA가 동작하려면 전역으로 설치된 npm이 필요할 수 있습니다.
IDE는 npm 실행 파일의 위치를 설정하는 대체 구성 옵션을 제공할 수 있습니다.
자세한 내용은 IDE 문서를 참조하세요.
ATA가 항상 동작한다는 보장이 없으며 Lodash는 많은 유틸리티 함수의 기반이므로, package.json의 devDependencies에 Lodash용 DefinitelyTyped 정의를 명시적으로 추가했습니다.
이를 통해 모든 사람이 즉시 lodash 기반 함수에 대한 타입 힌트를 제공받을 수 있습니다.