InfoGrab DocsInfoGrab Docs

타입 힌팅 개요

요약

GitLab 프로젝트의 프론트엔드 코드베이스는 현재 타입을 요구하거나 강제하지 않습니다. 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(/* ... */);
Note

import()는 JSDoc의 기본 구문이 아니지만 많은 IDE와 도구가 이를 인식합니다. 여기에서는 코드의 명확성을 높이고 IDE 에서의 개발자 경험을 개선하는 것을 목표로 합니다.

JSDoc의 한계#

앞에서 설명한 대로 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)#

GitLab 코드베이스는 import에 여러 별칭을 사용합니다. 예를 들어 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 pull에도 포함되지 않으므로 직접 생성하거나 갱신해야 합니다.

서드파티 TypeScript 정의#

점점 더 많은 라이브러리가 타입 정의에 TypeScript를 사용하고 있지만, 일부는 여전히 JSDoc으로 타입을 표기하거나 타입이 전혀 없습니다. 이 공백을 메우기 위해 TypeScript 커뮤니티는 DefinitelyTyped 이니셔티브를 시작해, 널리 쓰이는 JavaScript 라이브러리의 독립적인 타입 정의를 만들고 관리합니다. 이 정의는 타입 패키지를 직접 설치하거나(yarn add -D "@types/lodash"), 일부 언어 서비스에서 제공하는 Automatic Type Acquisition(ATA) 기능을 사용해 활용할 수 있습니다 (예: ATA in VS Code).

Automatic Type Acquisition(ATA)은 DefinitelyTyped 목록에서 타입 정의를 자동으로 가져옵니다. 다만 ATA가 동작하려면 전역으로 설치된 npm 이 필요할 수 있습니다. IDE는 npm 실행 파일의 위치를 지정하는 대체 구성 옵션을 제공하기도 합니다. 자세한 내용은 사용 중인 IDE 문서를 참고합니다.

ATA가 항상 동작한다고 보장할 수 없고 Lodash는 여러 유틸리티 함수의 기반이므로, Lodash 용 DefinitelyTyped 정의를 package.json의 devDependencies에 명시적으로 추가해 두었습니다. 이렇게 하면 모든 개발자가 별도 설정 없이 lodash 기반 함수의 타입 힌트를 받을 수 있습니다.

타입 힌팅 개요

GitLab v19.4
원문 보기

요약

GitLab 프로젝트의 프론트엔드 코드베이스는 현재 타입을 요구하거나 강제하지 않습니다. 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(/* ... */);
Note

import()는 JSDoc의 기본 구문이 아니지만 많은 IDE와 도구가 이를 인식합니다. 여기에서는 코드의 명확성을 높이고 IDE 에서의 개발자 경험을 개선하는 것을 목표로 합니다.

JSDoc의 한계#

앞에서 설명한 대로 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)#

GitLab 코드베이스는 import에 여러 별칭을 사용합니다. 예를 들어 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 pull에도 포함되지 않으므로 직접 생성하거나 갱신해야 합니다.

서드파티 TypeScript 정의#

점점 더 많은 라이브러리가 타입 정의에 TypeScript를 사용하고 있지만, 일부는 여전히 JSDoc으로 타입을 표기하거나 타입이 전혀 없습니다. 이 공백을 메우기 위해 TypeScript 커뮤니티는 DefinitelyTyped 이니셔티브를 시작해, 널리 쓰이는 JavaScript 라이브러리의 독립적인 타입 정의를 만들고 관리합니다. 이 정의는 타입 패키지를 직접 설치하거나(yarn add -D "@types/lodash"), 일부 언어 서비스에서 제공하는 Automatic Type Acquisition(ATA) 기능을 사용해 활용할 수 있습니다 (예: ATA in VS Code).

Automatic Type Acquisition(ATA)은 DefinitelyTyped 목록에서 타입 정의를 자동으로 가져옵니다. 다만 ATA가 동작하려면 전역으로 설치된 npm 이 필요할 수 있습니다. IDE는 npm 실행 파일의 위치를 지정하는 대체 구성 옵션을 제공하기도 합니다. 자세한 내용은 사용 중인 IDE 문서를 참고합니다.

ATA가 항상 동작한다고 보장할 수 없고 Lodash는 여러 유틸리티 함수의 기반이므로, Lodash 용 DefinitelyTyped 정의를 package.json의 devDependencies에 명시적으로 추가해 두었습니다. 이렇게 하면 모든 개발자가 별도 설정 없이 lodash 기반 함수의 타입 힌트를 받을 수 있습니다.