[번역] TypeScript 4.9

Jisu Yuk
24 min readNov 30, 2022

--

원문: https://devblogs.microsoft.com/typescript/announcing-typescript-4-9/

오늘 TypeScript 4.9를 발표하게 되어 기쁩니다!

TypeScript에 익숙하지 않은 사람을 위해 간단하게 소개하겠습니다. TypeScript는 타입이 추가되고 타입 검사를 수행하는 자바스크립트 기반의 언어입니다. 타입을 통해 객체의 모양, 함수 호출 방법, 프로퍼티가 null 또는 undefined인지의 여부와 같은 것을 설명할 수 있습니다. TypeScript를 통해 타입을 확인하기 때문에 프로그램에 실수가 없는 것을 보장하여 안심하고 코딩할 수 있습니다. 또한 에디터에서 자동 완성, 정의한 부분으로 이동, 리팩터링과 같은 도구들을 효율적으로 사용할 수 있게 도움을 줍니다. 실제로 Visual Studio 또는 자바스크립트용 VS Code와 같은 에디터를 사용한 적이 있다면 동일한 경험이 이미 TypeScript에 의해 제공됩니다!

TypeScript 4.9를 시작하려면 NuGet을 사용하거나 아래 명령어로 npm을 통해 사용할 수 있습니다.

npm install -D typescript

에디터의 지원을 받을 수도 있습니다.

다음은 TypeScript 4.9의 새로운 기능에 대한 목록입니다!

  • satisfies 연산자
  • in 연산자를 사용한 목록에 없는 프로퍼티 좁히기
  • 클래스의 자동 접근자
  • NaN에 대한 동등성 검사
  • 파일 감시는 이제 파일 시스템 이벤트를 사용합니다.
  • 에디터용 “Remove Unused Imports” 및 “Sort Imports” 명령어 추가
  • return 키워드에 대한 정의한 부분으로 이동 기능
  • 성능 개선
  • 정확 수정 및 브레이킹 체인지

Beta와 RC 이후의 새로 추가된 기능

RC 이후 TypeScript 4.9에는 변경 사항이 없습니다.

TypeScript 4.9 베타에는 원래 아래에 설명된 성능 향상과 함께 클래스에 자동 접근자가 포함되었습니다. 그러나 4.9 베타 게시물에는 포함되지 않았습니다.

원래 4.9 베타에는 에디터용 “Remove Unused Imports” 및 “Sort Imports” 명령어와 return 키워드에 대한 정의한 부분으로 이동 기능이 포함되지 않았습니다.

satisfies 연산자

TypeScript 개발자는 종종 딜레마에 직면합니다. 우리는 어떤 표현식이 어떤 타입과 일치하는지 확인하고 싶지만, 추론 목적을 위해 해당 표현식의 가장 구체적인 타입은 유지하기를 원합니다.

예를 들면 아래와 같습니다.

// 각각의 프로퍼티는 string 또는 RGB 튜플이 될 수 있습니다.
const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255],
// ^^^^ bleu - 오타를 만들었습니다!
};

// 우리는 'red'에 array 메서드를 사용할 수 있기를 원합니다.
const redComponent = palette.red.at(0);

// 우리는 'green'에 string 메서드를 사용할 수 있기를 원합니다.
const greenNormalized = palette.green.toUpperCase();

우리는 bleu라고 썼지만 아마도 blue라고 썼어야 했을 것입니다. palette의 type annotation을 사용하여 해당 bleu 오타를 잡으려고 시도할 수 있지만 각 프로퍼티에 대한 정보를 잃게 됩니다.

type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette: Record<Colors, string | RGB> = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255],
// ~~~~ 이제 오타가 정확하게 감지됩니다.
};

// 그러나 의도하지 않은 에러를 만나게 됩니다. 'palette.red'는 string이 되어야 합니다.
const redComponent = palette.red.at(0);

새로운 satisfies 연산자를 사용하면 해당 표현식의 반환 타입을 변경하지 않고 표현식 타입이 어떤 타입과 일치하는지 확인할 수 있습니다. 예를 들어 satisfies를 사용하여 팔레트의 모든 속성이 string 또는 number[] 인지 판단할 수 있습니다.

type Colors = "red" | "green" | "blue";

type RGB = [red: number, green: number, blue: number];

const palette = {
red: [255, 0, 0],
green: "#00ff00",
bleu: [0, 0, 255]
// ~~~~ 오타가 감지됩니다.
} satisfies Record<Colors, string | RGB>;

// 두개의 메서드 모두 사용 가능합니다.
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();

satisfies는 가능한 많은 오류를 포착하는 데 사용할 수 있습니다. 예를 들어 객체가 특정 유형의 모든 키를 가지고 있지만 더 이상 키가 없는지 확인할 수 있습니다.

type Colors = "red" | "green" | "blue";

// 키가 'Colors'인지 정확하게 확인합니다.
const favoriteColors = {
"red": "yes",
"green": false,
"blue": "kinda",
"platypus": false
// ~~~~~~~~~~ 에러 - "platypus"가 'Colors'에 존재하지 않습니다.
} satisfies Record<Colors, unknown>;

// 'red', 'green' 및 'blue' 프로퍼티에 대한 모든 정보가 유지됩니다.
const g: boolean = favoriteColors.green;

프로퍼티의 이름이 어떻게든 일치하는지 여부는 신경 쓰지 않을 수 있지만 각 프로퍼티의 타입에는 관심이 있습니다. 이 경우 객체의 모든 프로퍼티 값이 일부 타입을 준수하는지 확인할 수도 있습니다.

type RGB = [red: number, green: number, blue: number];

const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0]
// ~~~~~~ 에러 발생
} satisfies Record<string, string | RGB>;

// 각 프로퍼티에 대한 정보는 계속 유지됩니다.
const redComponent = palette.red.at(0);
const greenNormalized = palette.green.toUpperCase();

더 많은 예를 보려면 제안서pull request를 참고하세요. 우리와 함께 이 기능을 구현하고 함께한 Oleksandr Tarasiuk에게 감사드립니다.

in 연산자를 사용한 목록에 없는 프로퍼티 좁히기

개발자로서 우리는 종종 런타임에서 완전히 알 수 없는 값을 처리할 경우가 있습니다. 실제로 우리는 속성이 존재하는지, 서버에서 응답을 받는지 또는 설정 파일을 읽는지 알지 못하는 경우가 많습니다. 자바스크립트의 in 연산자는 객체에 프로퍼티가 있는지 여부를 확인할 수 있습니다.

이전에는 TypeScript를 사용하여 프로퍼티가 명시적으로 포함되지 않은 경우에 타입의 범위를 좁힐 수 있었습니다.

interface RGB {
red: number;
green: number;
blue: number;
}

interface HSV {
hue: number;
saturation: number;
value: number;
}

function setColor(color: RGB | HSV) {
if ("hue" in color) {
// 'color'의 타입은 HSV입니다.
}
// ...
}

여기서 RGB 타입은 hue를 포함하지 않기 때문에 범위가 좁아져서 HSV 타입만 남게 됩니다.

그러나 지정된 프로퍼티가 타입에 없는 경우는 어떻습니까? 그런 경우에는 별로 도움이 되지 않았습니다. 자바스크립트에서 다음 예제를 살펴보겠습니다.

function tryGetPackageName(context) {
const packageJSON = context.packageJSON;
// 객체인지 확인하세요.
if (packageJSON && typeof packageJSON === "object") {
// name 프로퍼티가 있는지 확인하세요.
if ("name" in packageJSON && typeof packageJSON.name === "string") {
return packageJSON.name;
}
}

return undefined;
}

이것을 정식 TypeScript로 다시 작성하는 것은 context에 대한 타입을 정의하고 사용하는 문제일 뿐입니다. 그러나 packageJSON 속성에 대해 unknown과 같은 안전한 타입을 선택하면 이전 버전의 TypeScript에서 문제가 발생할 수 있습니다.

interface Context {
packageJSON: unknown;
}

function tryGetPackageName(context: Context) {
const packageJSON = context.packageJSON;
// 객체인지 확인하세요.
if (packageJSON && typeof packageJSON === "object") {
// name 프로퍼티가 있는지 확인하세요.
if ("name" in packageJSON && typeof packageJSON.name === "string") {
// ~~~~
// 에러! 프로퍼티 'name'은 object 타입에 존재하지 않습니다.
return packageJSON.name;
// ~~~~
// 에러! 프로퍼티 'name'은 object 타입에 존재하지 않습니다.
}
}

return undefined;
}

이는 packageJSON의 타입이 unknown에서 object로 좁혀진 반면 in 연산자는 확인 중인 속성을 실제로 정의한 유형으로 엄격하게 좁혀졌기 때문입니다. 결과적으로 packageJSON의 타입은 객체로 남았습니다.

TypeScript 4.9는 프로퍼티를 전혀 나열하지 않는 타입을 좁힐 때 in 연산자를 조금 더 강력하게 만듭니다. 아무런 변경 없이 언어 내부적으로 Record<”property-key-being-checked”, unknown> 타입으로 교차 될 것입니다.

따라서 우리의 예에서 packageJSON의 타입은 unknown에서 object로 그리고 object & Record<”name”, unknown>으로 좁혀져 packageJSON.name에 직접 액세스하고 독립적으로 좁혀질 수 있습니다.

interface Context {
packageJSON: unknown;
}

function tryGetPackageName(context: Context) {
const packageJSON = context.packageJSON;
// 객체인지 확인하세요.
if (packageJSON && typeof packageJSON === "object") {
// name 프로퍼티가 있는지 확인하세요.
if ("name" in packageJSON && typeof packageJSON.name === "string") {
// 정상적으로 동작합니다!
return packageJSON.name;
}
}

return undefined;
}

TypeScript 4.9는 또한 in 사용 방법에 대한 몇 가지 검사를 강화하여 좌측에는 string | number | symbol을 오른쪽에는 object에 할당할 수 있습니다. 이렇게 하면 유효한 프로퍼티 키를 사용하고 있는지 확인하고 실수로 프리미티브를 확인하지 않았는지 확인하는 데 도움이 됩니다.

자세한 내용은 pull request를 참조하세요.

클래스의 자동 접근자

TypeScript 4.9는 자동 접근자라고 하는 ECMAScript의 향후 기능을 지원합니다. 자동 접근자는 accessor 키워드로 선언된다는 점을 제외하면 클래스의 프로퍼티처럼 선언됩니다.

class Person {
accessor name: string;

constructor(name: string) {
this.name = name;
}
}

좀 더 자세히 살펴보면 자동 접근자는 접근할 수 없는 private 속성이 있는 get 및 set 접근자로 문법적 설탕을 제거하여 볼 수 있습니다.

자동 접근자 pull request에서 자세한 내용을 확인할 수 있습니다.

NaN에 대한 동등성 검사

자바스크립트를 사용하는 개발자의 주요 문제점은 기본으로 제공하는 동등 연산자를 사용하여 NaN 값을 확인하는 것입니다.

NaN은 “Not a Number”를 나타내는 특수 숫자 값입니다. NaN과 같은 것은 없습니다. 심지어 NaN도 마찬가지입니다!

console.log(NaN == 0); // false
console.log(NaN === 0); // false

console.log(NaN == NaN); // false
console.log(NaN === NaN); // false

그러나 적어도 대칭적으로는 모든 것이 항상 NaN과 같지 않습니다.

console.log(NaN != 0); // true
console.log(NaN !== 0); // true

console.log(NaN != NaN); // true
console.log(NaN !== NaN); // true

IEEE-754 float를 포함하는 모든 언어가 동일한 동작을 하므로 이것은 기술적으로 자바스크립트 관련 문제가 아닙니다. 그러나 자바스크립트의 기본 number 타입은 부동 소수점 숫자이며 자바스크립트의 숫자 구문 분석은 종종 NaN을 초래할 수 있습니다. 결과적으로 NaN에 대한 확인은 매우 일반적이며 이를 수행하는 올바른 방법은 Number.isNaN을 사용하는 것입니다. 그러나 우리가 언급했듯이 많은 사람들이 실수로 대신 someValue === NaN으로 확인하게 됩니다.

TypeScript에서는 이제 NaN에 대해 직접 비교하게 되는 경우 오류가 발생할 것이고 대신에 Number.isNaN을 사용할 것을 제안합니다.

function validate(someValue: number) {
return someValue !== NaN;
// ~~~~~~~~~~~~~~~~~
// 에러: 이 조건은 항상 'true'를 반환할 것입니다.
// 당신이 원하는 것은 '!Number.isNaN(someValue)' 아닌가요?
}

우리는 이 변경이 TypeScript가 현재 객체 및 배열 비교에서 오류를 발생시키는 방식과 유사하게 초보적인 오류를 잡는 데 큰 도움이 될 것이라고 믿습니다.

이 기능에 기여Oleksandr Tarasiuk에게 감사를 전하고 싶습니다.

파일 감시는 이제 파일 시스템 이벤트를 사용합니다

이전 버전에서 TypeScript는 개별 파일을 감시하기 위해 폴링에 크게 의존했습니다. 폴링 전략을 사용한다는 것은 업데이트를 위해 주기적으로 파일 상태를 확인하는 것을 의미했습니다. Node.js에서 fs.watchFile은 폴링 파일 감시자를 가져오는 기본 제공 방법입니다. 폴링은 플랫폼과 파일 시스템 전반에서 더 예측 가능한 경향이 있지만, 이는 아무것도 변경되지 않은 경우에도 CPU가 주기적으로 중단되고 파일 업데이트를 확인해야 함을 의미합니다. 수십 개의 파일의 경우 눈에 띄지 않을 수 있습니다. 그러나 파일이 많거나 node_modules에 파일이 많은 더 큰 프로젝트에서는 리소스를 많이 차지할 수 있습니다.

일반적으로 더 나은 접근 방식은 파일 시스템 이벤트를 사용하는 것입니다. 폴링하는 대신 특정 파일의 업데이트에 관심이 있음을 알리고 해당 파일이 실제로 변경되는 시점에 대한 콜백을 제공할 수 있습니다. 사용 중인 대부분의 최신 플랫폼은 CreateIoCompletionPort, kqueue, epollinotify와 같은 기능과 API를 제공합니다. Node.js는 대부분 fs.watch를 제공하여 이를 추상화합니다. 파일 시스템 이벤트는 일반적으로 훌륭하게 작동하지만 이를 사용하고 fs.watch API를 사용하는 데 많은 주의 사항이 있습니다. 감시자는 inode 감시, 특정 파일 시스템에서 사용할 수 없음(예: 네트워크 파일 시스템), 재귀 파일 감시가 사용 가능한지 여부, 디렉터리 이름 변경이 이벤트를 트리거 하는지 여부, 파일 감시자 고갈까지 고려해야 합니다! 즉, 특히 크로스 플랫폼을 찾고 있다면 절대 쉽지 않습니다.

결과적으로 우리의 기본값은 폴링이라는 가장 낮은 공통분모를 선택하는 것이었습니다. 항상 그런 것은 아니지만 대부분의 경우입니다.

시간이 지남에 따라 우리는 다른 파일 감시 전략을 선택할 수 있는 수단을 제공했습니다. 이를 통해 우리는 피드백을 받고 이러한 플랫폼별 문제 대부분에 대해 파일 감시 구현을 강화할 수 있었습니다. TypeScript는 더 큰 코드 베이스로 확장해야 하고 이 영역에서 개선되었으므로 파일 시스템 이벤트를 기본값으로 바꾸는 것이 가치 있는 투자라고 생각했습니다.

TypeScript 4.9에서 파일 감시는 기본적으로 파일 시스템 이벤트에 의해 구동되며 이벤트 기반 감시자를 설정하지 못한 경우에만 폴링으로 돌아갑니다. 대부분의 개발자에게 이것은 — watch 모드에서 실행하거나 Visual Studio 또는 VS Code와 같은 TypeScript 기반 편집기로 실행할 때 훨씬 덜 리소스 집약적인 환경을 제공해야 합니다.

파일 감시 작동 방식은 여전히 ​​환경 변수 및 watchOptions를 통해 구성할 수 있으며 VS Code와 같은 일부 편집기는 watchOptions를 독립적으로 지원할 수 있습니다. NFS 및 SMB와 같은 네트워크 파일 시스템에 소스 코드가 상주하는 좀 더 특이한 설정을 사용하는 개발자는 이전 동작을 다시 선택해야 할 수 있습니다. 하지만 서버에 적절한 처리 능력이 있는 경우 SSH를 활성화하고 TypeScript를 원격으로 실행하여 직접 로컬 파일에 액세스 할 수 있도록 하는 것이 더 나을 수 있습니다. VS Code에는 이 작업을 더 쉽게 수행할 수 있는 원격 확장이 많이 있습니다.

GitHub에서 이 변경 사항에 대해 자세히 알아볼 수 있습니다.

에디터용 “Remove Unused Imports” 및 “Sort Imports” 명령어 추가

이전에 TypeScript는 import를 관리하기 위해 두 개의 에디터 명령어만 지원했습니다. 예를 들어 다음 코드를 참고하세요.

import { Zebra, Moose, HoneyBadger } from "./zoo";
import { foo, bar } from "./helper";

let x: Moose | HoneyBadger = foo();

첫 번째는 사용하지 않는 import를 제거한 다음 나머지 import를 정렬하는 “Organize imports”라고 합니다. 다음과 같이 파일이 다시 작성됩니다.

import { foo } from "./helper";
import { HoneyBadger, Moose } from "./zoo";

let x: Moose | HoneyBadger = foo();

TypeScript 4.3에서는 파일에서 import를 정렬만 하고 제거하지는 않는 “Sort Imports”라는 명령어를 도입했으며 파일을 아래와 같이 다시 작성합니다.

import { bar, foo } from "./helper";
import { HoneyBadger, Moose, Zebra } from "./zoo";

let x: Moose | HoneyBadger = foo();

“Sort Imports”에 대한 주의 사항은 Visual Studio Code에서 이 기능이 수동으로 트리거 할 수 있는 명령이 아니라 저장 시 명령으로만 사용할 수 있다는 것입니다.

TypeScript 4.9는 나머지 절반을 추가하여 이제 “Remove Unused Imports”를 제공합니다. TypeScript는 이제 사용하지 않는 import 이름과 명령문을 제거하지만 그렇지 않은 경우 상대적 순서는 그대로 둡니다.

import { Moose, HoneyBadger } from "./zoo";
import { foo } from "./helper";

let x: Moose | HoneyBadger = foo();

이 기능은 두 명령어 중 하나를 사용하려는 모든 편집자가 사용할 수 있습니다. 그러나 특히 Visual Studio Code(1.73 이상)에는 기본 지원 기능이 있으며 명령 palette를 통해 이러한 명령을 표시합니다. 보다 세분화된 “Remove Unused Imports” 또는 “Sort Imports” 명령어를 선호하는 사용자는 원하는 경우 “Organize Imports” 키 조합을 재 할당할 수 있어야 합니다.

여기에서 기능의 세부 사항을 볼 수 있습니다.

## return 키워드에 대한 정의한 부분으로 이동 기능

에디터에서 return 키워드에 대해 정의한 부분으로 이동 기능을 실행할 때 TypeScript는 이제 해당 함수의 맨 위로 이동합니다. 이는 return이 속한 함수를 빠르게 파악하는 데 도움이 될 수 있습니다.

TypeScript는 이 기능을 await 및 yield 또는 switch, case 및 default와 같은 더 많은 키워드로 확장할 것으로 기대합니다.

이 기능Oleksandr Tarasiuk 덕분에 구현되었습니다.

성능 개선

몇 가지 작지만 주목할 만한 성능 향상이 있습니다.

첫째, TypeScript의 forEachChild 함수는 모든 구문 노드에서 switch 문 대신 함수 테이블 조회를 사용하도록 다시 작성되었습니다. forEachChild는 컴파일러에서 구문 노드를 탐색하기 위한 작업 도구이며 언어 서비스의 일부와 함께 컴파일러의 바인딩 단계에서 많이 사용됩니다. forEachChild의 리팩터링은 바인딩 단계와 언어 서비스 작업 전반에 드는 시간을 최대 20% 단축했습니다.

forEachChild의 성능 향상을 발견한 후 컴파일러 및 언어 서비스에서 노드를 변환하는 데 사용하는 함수인 visitEachChild에서 이를 시도했습니다. 동일한 리팩터링으로 프로젝트 결과를 생성하는 데 소요되는 시간이 최대 3% 감소했습니다.

forEachChild의 초기 탐색은 Artemis Everfree블로그 게시물에서 영감을 받았습니다. 속도 향상의 근본 원인이 블로그 게시물에 설명된 문제보다 기능 크기/복잡성과 더 관련이 있다고 믿을만한 이유가 있지만 경험을 통해 배울 수 있었고 TypeScript를 더 빠르게 만드는 비교적 빠른 리팩터링을 시도할 수 있었던 것에 감사합니다.

마지막으로 TypeScript가 조건부 타입이 실제 분기에서 타입에 대한 정보를 보존하는 방식이 최적화되었습니다. 아래와 같습니다.

interface Zoo<T extends Animal> {
// ...
}

type MakeZoo<A> = A extends Animal ? Zoo<A> : never;

TypeScript는 Zoo<A>가 유효한지 확인할 때 AAnimal이어야 함을 “기억”해야 합니다. 이것은 기본적으로 AAnimal의 교차점을 유지하는 데 사용되는 특수 타입을 생성하여 수행됩니다. 그러나 TypeScript는 이전에 이 작업을 열심히 수행했으며 항상 필요한 것은 아닙니다. 또한 타입 검사기의 일부 잘못된 코드로 인해 이러한 특수 타입이 단순화되지 않았습니다. TypeScript는 이제 필요할 때까지 이러한 타입의 교차를 연기합니다. 조건부 타입을 많이 사용하는 코드 베이스의 경우 TypeScript를 사용하여 상당한 속도 향상을 목격할 수 있지만 성능 테스트 제품군에서는 타입 검사 시간이 3% 더 완만하게 감소했습니다.

각각의 pull request에서 이러한 최적화에 대해 자세히 알아볼 수 있습니다.

정확 수정 및 브레이킹 체인지

lib.d.ts 업데이트

TypeScript는 큰 브레이킹 체인지를 피하고자 노력하지만, 내장 라이브러리의 작은 변경도 문제를 일으킬 수 있습니다. DOM 및 lib.d.ts 업데이트의 결과로 큰 브레이킹 체인지가 예상되지는 않지만, 일부 작은 브레이킹 체인지가 있을 수 있습니다.

Promise.resolve의 더 나은 타입

Promise.resolve는 이제 Awaited 타입을 사용하여 전달된 Promise와 유사한 타입의 래핑을 해제합니다. 즉, 더 자주 올바른 Promise 타입을 반환하지만 Promise 대신 any 또는 unknown을 기대하는 경우 개선된 타입이 기존 코드를 손상시킬 수 있습니다. 자세한 내용은 변경 사항을 참조하세요.

자바스크립트 Emit이 더 이상 가져오기를 제거하지 않음

TypeScript가 자바스크립트에 대한 타입 검사 및 컴파일을 처음 지원했을 때 실수로 import elision이라는 기능을 지원했습니다. 즉, import가 값으로 사용되지 않거나 런타임에 import가 값을 참조하지 않는다는 것을 컴파일러가 감지할 수 있는 경우 컴파일러는 export 하는 동안 import를 삭제합니다.

이 동작은 특히 import가 값을 참조하지 않는지 여부를 감지하는 데 의심스러웠습니다. 이는 TypeScript가 때때로 부정확한 선언 파일을 신뢰해야 함을 의미하기 때문입니다. TypeScript는 이제 자바스크립트 파일의 import를 유지합니다.

// Input:
import { someValue, SomeClass } from "some-module";

/** @type {SomeClass} */
let val = someValue;

// 이전의 결과:
import { someValue } from "some-module";

/** @type {SomeClass} */
let val = someValue;

// 현재 결과:
import { someValue, SomeClass } from "some-module";

/** @type {SomeClass} */
let val = someValue;

자세한 내용은 여기에서 확인할 수 있습니다.

exports는 typesVersions보다 우선순위가 높습니다

이전에는 TypeScript가 --moduleResolution node16 아래의 package.json을 통해 확인할 때 exports 필드보다 typesVersions 필드의 우선순위가 높게 잘못 지정했습니다. 이 변경 사항이 라이브러리에 영향을 미치는 경우 package.jsonexports 필드에 types@ 버전 선택자를 추가해야 할 수 있습니다.

{
"type": "module",
"main": "./dist/main.js",
"typesVersions": {
"<4.8": { ".": ["4.8-types/main.d.ts"] },
"*": { ".": ["modern-types/main.d.ts"] }
},
"exports": {
".": {
+ "types@<4.8": "4.8-types/main.d.ts",
+ "types": "modern-types/main.d.ts",
"import": "./dist/main.js"
}
}
}

자세한 내용은 이 pull request를 참고하세요.

SubstitutionTypes의 substitute에서 constraint 로 교체

substitution 타입에 대한 최적화의 일부로 SubstitutionType 객체는 효과적인 대체(일반적으로 기본 유형과 암시적 제약 조건의 교차)를 나타내는 substitute 속성을 더 이상 포함하지 않습니다. 대신 constraint 조건 프로퍼티만 포함합니다.

자세한 내용은 여기를 자세히 읽어보세요.

향후 계획

우리의 다음 릴리스는 TypeScript 5.0이 될 것입니다. 그러나 두려워하지 마세요. 5.0은 채택하기가 매우 쉬울 것입니다. 5.0 계획을 주시하여 작업 중인 내용을 확인하세요.

그때까지 4.9 버전으로 즐겁게 코딩하기를 바랍니다.

Happy Hacking!

--

--