TypeScript 5.9 릴리스를 발표합니다. 간소화된 tsc --init, import defer 지원, --module node20, DOM API 요약 설명, 확장 가능한 호버와 최대 길이 설정, 성능 최적화, 그리고 주목할 동작 변경 사항을 소개합니다.
2025년 8월 1일
반응 9개

수석 제품 관리자
오늘 TypeScript 5.9 릴리스를 발표하게 되어 매우 기쁩니다!
TypeScript가 익숙하지 않다면, TypeScript는 JavaScript에 타입을 위한 구문을 추가한 언어입니다. 타입 덕분에 TypeScript는 사전에 코드를 점검해 버그를 방지할 수 있습니다. TypeScript 타입 검사기는 이러한 모든 일을 수행하며, 에디터 등에서 훌륭한 도구들의 기반이 되어 코딩을 더욱 쉽게 만들어 줍니다. Visual Studio나 VS Code 같은 에디터에서 JavaScript를 작성해 보셨다면, TypeScript는 이미 사용하고 있을지도 모르는 자동 완성, 정의로 이동 등의 기능을 제공하기도 합니다. TypeScript에 대해 더 알아보려면 웹사이트를 방문하세요.
이미 익숙하시다면, 오늘 바로 TypeScript 5.9를 사용해 보세요!
npm install -D typescript
이제 TypeScript 5.9의 새로운 기능을 살펴보겠습니다!
tsc --initimport defer 지원--module node20 지원릴리스 후보 이후 TypeScript 5.9에는 변경 사항이 없습니다.
보고된 이슈에 대한 몇 가지 수정이 5.9 베타 이후 반영되었으며, DOM 라이브러리에 AbortSignal.abort()가 복원되었습니다. 또한 주의할 동작 변경 사항 섹션을 추가했습니다.
tsc --init그동안 TypeScript 컴파일러는 현재 디렉터리에 tsconfig.json을 생성할 수 있는 --init 플래그를 지원해 왔습니다. 최근 몇 년간 tsc --init을 실행하면 주석 처리된 설정과 설명이 가득한 매우 “방대한” tsconfig.json이 생성되었습니다. 옵션을 쉽게 발견하고 토글할 수 있도록 설계된 결과였습니다.
하지만 외부 피드백(그리고 우리의 경험)을 바탕으로, 많은 사용자가 새 tsconfig.json의 대부분을 곧바로 삭제한다는 사실을 알게 되었습니다. 사용자가 새로운 옵션을 찾고자 할 때, 에디터의 자동 완성에 의존하거나 웹사이트의 tsconfig 참고 문서로 이동합니다(생성된 tsconfig.json에도 링크되어 있습니다!). 각 설정이 하는 일 역시 같은 페이지에 문서화되어 있으며, 에디터의 호버/툴팁/퀵 인포에서도 확인할 수 있습니다. 일부 주석 처리된 설정을 노출하는 것이 도움이 될 수 있지만, 생성된 tsconfig.json은 종종 과하다고 여겨졌습니다.
또한 tsc --init이 지금보다 더 규범적인 몇 가지 설정을 초기값으로 제공할 때가 되었다고 느꼈습니다. 새로운 TypeScript 프로젝트를 만들 때 사용자가 겪는 일반적인 불편과 작은 문제들을 검토했습니다. 예를 들어, 대부분의 사용자는 모듈(전역 스크립트가 아님)에서 코드를 작성하며, --moduleDetection은 모든 구현 파일을 모듈로 취급하도록 강제할 수 있습니다. 개발자는 종종 최신 ECMAScript 기능을 런타임에서 직접 사용하고자 하므로 --target은 일반적으로 esnext로 설정할 수 있습니다. JSX 사용자는 종종 뒤늦게 --jsx를 설정하는 과정이 불필요한 마찰이라고 느끼며, 그 옵션들도 약간 혼란스럽습니다. 또한 프로젝트는 종종 TypeScript가 실제로 필요로 하는 것보다 더 많은 선언 파일을 node_modules/@types에서 로드하게 되는데, 비어 있는 types 배열을 지정하면 이를 제한하는 데 도움이 됩니다.
TypeScript 5.9에서는 추가 플래그 없이 tsc --init만 실행하면 다음과 같은 tsconfig.json이 생성됩니다:
{
// https://aka.ms/tsconfig 에서 이 파일에 대해 더 알아보세요
"compilerOptions": {
// 파일 레이아웃
// "rootDir": "./src",
// "outDir": "./dist",
// 환경 설정
// https://aka.ms/tsconfig_modules 도 참고하세요
"module": "nodenext",
"target": "esnext",
"types": [],
// Node.js의 경우:
// "lib": ["esnext"],
// "types": ["node"],
// 그리고 npm install -D @types/node
// 기타 출력
"sourceMap": true,
"declaration": true,
"declarationMap": true,
// 더 엄격한 타입 검사 옵션
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
// 스타일 옵션
// "noImplicitReturns": true,
// "noImplicitOverride": true,
// "noUnusedLocals": true,
// "noUnusedParameters": true,
// "noFallthroughCasesInSwitch": true,
// "noPropertyAccessFromIndexSignature": true,
// 권장 옵션
"strict": true,
"jsx": "react-jsx",
"verbatimModuleSyntax": true,
"isolatedModules": true,
"noUncheckedSideEffectImports": true,
"moduleDetection": "force",
"skipLibCheck": true,
}
}
import defer 지원TypeScript 5.9는 새로운 import defer 구문을 사용하여 ECMAScript의 지연 모듈 평가 제안을 지원합니다. 이 기능을 사용하면 모듈과 그 의존성을 즉시 실행하지 않고 가져올 수 있어 작업과 부작용이 발생하는 시점을 더 잘 제어할 수 있습니다.
이 구문은 네임스페이스 임포트만 허용합니다:
import defer * as feature from "./some-feature.js";
import defer의 핵심 이점은, 가져온 네임스페이스의 내보낸 값 중 하나를 처음 접근할 때에만 모듈이 평가된다는 점입니다. 다음 예제를 살펴보세요:
// ./some-feature.ts
initializationWithSideEffects();
function initializationWithSideEffects() {
// ...
specialConstant = 42;
console.log("Side effects have occurred!");
}
export let specialConstant: number;
import defer를 사용할 경우, 가져온 네임스페이스의 속성에 실제로 접근하기 전까지는 initializationWithSideEffects() 함수가 호출되지 않습니다:
import defer * as feature from "./some-feature.js";
// 아직 부작용은 발생하지 않았습니다
// ...
// `specialConstant`에 접근하는 순간, `feature` 모듈의 내용이 실행되고
// 부작용이 발생합니다.
console.log(feature.specialConstant); // 42
모듈의 평가는 해당 모듈의 멤버에 접근할 때까지 지연되기 때문에, import defer와 함께 이름 기반 임포트나 기본 임포트를 사용할 수 없습니다:
// 허용되지 않음
import defer { doSomething } from "some-module";
// 허용되지 않음
import defer defaultExport from "some-module";
// 이 구문만 지원됩니다
import defer * as feature from "some-module";
import defer를 작성하면 모듈과 그 의존성이 완전히 로드되어 실행 준비가 된다는 점에 유의하세요. 즉, 모듈은 존재해야 하며 파일 시스템 또는 네트워크 리소스에서 로드됩니다. 일반 import와 import defer의 주요 차이는, 가져온 네임스페이스의 속성에 접근할 때까지 “문과 선언의 실행”이 지연된다는 것입니다.
이 기능은 비용이 크거나 플랫폼별 초기화가 필요한 모듈을 조건부로 로드하는 데 특히 유용합니다. 또한 앱 기능에 대해 실제로 필요할 때까지 모듈 평가를 지연함으로써 시작 성능을 향상시킬 수 있습니다.
TypeScript는 import defer를 전혀 변환하거나 “다운레벨”하지 않는다는 점을 유의하세요. 이 기능은 해당 기능을 네이티브로 지원하는 런타임이나, 적절한 변환을 적용할 수 있는 번들러 같은 도구와 함께 사용하도록 의도되었습니다. 따라서 import defer는 --module 모드 중 preserve와 esnext에서만 동작합니다.
이 제안을 TC39에서 주도하고 이 기능의 구현도 제공해 주신 Nicolò Ribaudo께 감사드립니다.
--module node20 지원TypeScript는 --module 및 --moduleResolution 설정에 대해 여러 node* 옵션을 제공합니다. 가장 최근에는 --module nodenext가 CommonJS 모듈에서 ECMAScript 모듈을 require()할 수 있는 기능을 지원하고, 표준에 묶인 import attributes를 선호하여 import assertion을 올바르게 거부합니다.
TypeScript 5.9는 Node.js v20의 동작을 모델링하도록 의도된 node20이라는 안정적인 옵션을 도입합니다. 이 옵션은 --module nodenext 또는 --moduleResolution nodenext와 달리, 앞으로 새로운 동작이 추가될 가능성이 낮습니다. 또한 nodenext와 달리, --module node20을 지정하면 별도로 구성하지 않는 한 --target es2023이 내포됩니다. 반면 --module nodenext는 유동적인 --target esnext를 내포합니다.
자세한 정보는 여기 구현을 참고하세요.
이전에 TypeScript의 많은 DOM API는 해당 API의 MDN 문서로만 연결되어 있었습니다. 이러한 링크는 유용했지만, API가 무엇을 하는지에 대한 간단한 요약을 제공하지는 않았습니다. Adam Naji의 몇 가지 변경 덕분에, TypeScript는 이제 MDN 문서를 바탕으로 많은 DOM API에 대한 요약 설명을 포함합니다. 이러한 변경에 대해 더 보려면 여기와 여기를 참고하세요.
Quick Info(“에디터 툴팁” 또는 “호버”)는 변수에 마우스를 올려 타입을 확인하거나, 타입 별칭이 실제로 무엇을 가리키는지 확인하는 데 매우 유용합니다. 그럼에도 불구하고, 사람들은 퀵 인포 툴팁에 표시되는 내용에서 더 깊이 들어가 세부 정보를 얻고 싶어 하는 경우가 흔합니다. 예를 들어, 다음 예제에서 매개변수 options 위에 마우스를 올리면:
export function drawButton(options: Options): void
결과는 (parameter) options: Options뿐입니다.
타입 Options의 멤버가 무엇인지 보기 위해 정말로 타입 정의로 이동해야 할까요?
이전에는 실제로 그랬습니다. 이를 개선하기 위해, TypeScript 5.9에서는 “확장 가능한 호버”, 또는 “퀵 인포 상세도”라는 기능을 미리보기로 제공합니다. VS Code 같은 에디터를 사용하면 이제 이러한 호버 툴팁의 왼쪽에 +와 - 버튼이 표시됩니다. + 버튼을 클릭하면 타입이 더 깊게 확장되고, - 버튼을 클릭하면 이전 보기로 축소됩니다.
이 기능은 현재 미리보기 상태이며, TypeScript와 Visual Studio Code 파트너 모두에 대한 피드백을 구하고 있습니다. 자세한 내용은 이 기능의 PR을 참고하세요.
때때로 퀵 인포 툴팁이 너무 길어져 TypeScript가 가독성을 위해 내용을 잘라내는 경우가 있습니다. 문제는 이로 인해 종종 가장 중요한 정보가 호버 툴팁에서 생략되어 답답할 수 있다는 점입니다. 이를 개선하기 위해, TypeScript 5.9의 언어 서버는 VS Code의 js/ts.hover.maximumLength 설정을 통해 구성 가능한 호버 길이를 지원합니다.
또한 새로운 기본 호버 길이는 이전 기본값보다 상당히 커졌습니다. 즉, TypeScript 5.9에서는 기본적으로 호버 툴팁에서 더 많은 정보를 볼 수 있습니다. 자세한 내용은 이 기능의 PR과 Visual Studio Code의 해당 변경을 참고하세요.
TypeScript가 타입 매개변수를 구체적인 타입 인수로 치환할 때, 동일한 중간 타입들을 여러 번 인스턴스화하게 될 수 있습니다. Zod와 tRPC 같은 복잡한 라이브러리에서는 성능 문제와 과도한 타입 인스턴스화 깊이에 대한 오류로 이어질 수 있었습니다. Mateusz Burzyński의 변경 덕분에, TypeScript 5.9는 특정 타입 인스턴스화에 대한 작업이 이미 시작된 경우 많은 중간 인스턴스화를 캐시할 수 있게 되었습니다. 이는 불필요한 작업과 할당을 크게 줄입니다.
fileOrDirectoryExistsUsingSource에서 클로저 생성 회피JavaScript에서 함수 표현식은 래퍼 함수가 캡처한 변수가 없이 단지 인수만 다른 함수로 전달하는 경우조차도 보통 새로운 함수 객체를 할당합니다. 파일 존재 여부 확인 경로에서, Vincent Bailly는 기저 함수가 단일 인수만 받는데도 이러한 패스스루 함수 호출이 있는 사례를 발견했습니다. 더 큰 프로젝트에서 발생할 수 있는 존재 확인 횟수를 고려할 때, 약 11%의 속도 향상을 보고했습니다. 이 변경에 대해 더 보기.
lib.d.ts 변경 사항DOM을 위해 생성된 타입은 코드베이스의 타입 검사에 영향을 줄 수 있습니다.
또한 주목할 만한 변경으로, ArrayBuffer가 더 이상 여러 서로 다른 TypedArray 타입의 상위 타입이 아니도록 변경되었습니다. 여기에는 Node.js의 Buffer처럼 UInt8Array의 하위 타입도 포함됩니다. 그 결과, 다음과 같은 새로운 오류 메시지를 보게 될 수 있습니다:
error TS2345: Argument of type 'ArrayBufferLike' is not assignable to parameter of type 'BufferSource'.
error TS2322: Type 'ArrayBufferLike' is not assignable to type 'ArrayBuffer'.
error TS2322: Type 'Buffer' is not assignable to type 'Uint8Array<ArrayBufferLike>'.
error TS2322: Type 'Buffer' is not assignable to type 'ArrayBuffer'.
error TS2345: Argument of type 'Buffer' is not assignable to parameter of type 'string | Uint8Array<ArrayBufferLike>'.
Buffer 관련 문제가 발생한다면, 먼저 @types/node 패키지의 최신 버전을 사용하고 있는지 확인하세요. 다음을 실행해야 할 수도 있습니다.
npm update @types/node --save-dev
대부분의 경우, 기본 ArrayBufferLike 대신 더 구체적인 하위 버퍼 타입을 지정하는 것이 해결책입니다(예: 단순한 Uint8Array 대신 명시적으로 Uint8Array<ArrayBuffer>를 작성). 어떤 경우에는 ArrayBuffer 또는 SharedArrayBuffer를 기대하는 함수에 일부 TypedArray(예: Uint8Array)를 전달할 때, 다음 예시처럼 해당 TypedArray의 buffer 속성에 접근해 볼 수도 있습니다:
let data = new Uint8Array([0, 1, 2, 3, 4]);
- someFunc(data)
+ someFunc(data.buffer)
추론 중 타입 변수의 “누수”를 수정하기 위한 노력의 일환으로, TypeScript 5.9는 일부 코드베이스에서 타입 변경과 새로운 오류를 유발할 수 있습니다. 이는 예측하기 어렵지만, 대부분의 경우 제네릭 함수 호출에 타입 인수를 추가하여 해결할 수 있습니다. 자세한 내용은 여기에서 확인하세요.
이제 TypeScript 5.9가 출시되었으니, 다음 버전인 TypeScript 6.0에는 무엇이 포함될지 궁금하실 겁니다.
들으셨겠지만, 최근 우리의 주요 초점은 TypeScript의 네이티브 포트에 맞춰져 있으며, 이는 결국 TypeScript 7.0으로 제공될 예정입니다. 그렇다면 TypeScript 6.0은 무엇을 의미할까요?
TypeScript 6.0에 대한 우리의 비전은, 개발자가 TypeScript 7.0을 도입하기 위해 코드베이스를 조정할 수 있는 전환점으로 작동하는 것입니다. TypeScript 6.0도 업데이트와 기능을 제공할 수 있지만, 대부분의 사용자는 이를 TypeScript 7.0 채택을 위한 준비 상태 점검으로 생각하면 됩니다. 이 새로운 버전은 TypeScript 7.0과의 정렬을 목표로 하며, 특정 설정에 대한 사용 중단을 도입하고 타입 검사 동작을 소폭 업데이트할 수도 있습니다. 다행히도 대부분의 프로젝트는 TypeScript 6.0으로 업그레이드하는 데 큰 어려움이 없을 것으로 예상하며, TypeScript 5.9와 완전히 API 호환일 가능성이 큽니다.
곧 더 많은 세부 정보를 공유하겠습니다. 여기에는 TypeScript 7.0에 대한 세부 정보도 포함되며, 오늘 Visual Studio Code에서 미리 써보고 프로젝트에 바로 설치할 수 있습니다.
그 밖에도 TypeScript 5.9가 여러분께 좋은 경험을 제공하고, 매일의 코딩을 즐겁게 만들어 주기를 바랍니다.
해피 해킹!
– Daniel Rosenwasser 및 TypeScript 팀
카테고리

수석 제품 관리자
Daniel Rosenwasser는 TypeScript 팀의 제품 관리자입니다. 그는 프로그래밍 언어, 컴파일러, 그리고 훌륭한 개발자 도구에 열정을 가지고 있습니다.