프론트엔드/Typescript

4.5 번역

테오구 2022. 5. 5. 15:23
728x90

TypeScript 4.5에는 @type/support의 작동 방식과 유사한 방식으로 특정 기본 제공 lib를 재정의하는 방법이 도입되었습니다.

TypeScript에 포함되어야 할 lib 파일을 결정할 때 먼저 node_modules에서 범위가 지정된 @typescript/lib-* 패키지를 찾습니다. 예를 들어, lib의 옵션으로 dom을 포함할 때 TypeScript는 node_modules/@typescript/lib-dom에 있는 형식을 사용합니다.

그런 다음 패키지 관리자를 사용하여 지정된 lib를 대신할 특정 패키지를 설치할 수 있습니다.

예를 들어, 오늘날 TypeScript는 DOM API의 버전을 @type/web에 게시합니다.

예를 들어, 오늘날 TypeScript는 DOM API의 버전을 @type/web에 게시합니다.

프로젝트를 특정 버전의 DOM API로 잠그려는 경우 package.json에 추가할 수 있습니다.

{
  "dependencies": {
    "@typescript/lib-dom": "npm:@types/web"
  }
}

TheAwaitedType andPromiseImprovements

TypeScript 4.5에는 Waited type이라는 새로운 유틸리티 타입이 도입되었습니다.

이 타입은 비동기 함수에서 waiting 또는 Promise에서 .then() 메소드와 같은 작업을 모델링하기 위한 것으로, 특히 약속의 래핑을 반복적으로 해제하는 방식을 의미합니다.

// A = string
type A = Awaited<Promise<string>>;
// B = number
type B = Awaited<Promise<Promise<number>>>;
// C = boolean | number
type C = Awaited<boolean | Promise<number>>;

Awaited 타입은 유용할 수 있다 APIs를 설계하는데 Promise.all, Promise.race, etc를 포함하여

Template String Types as Discriminants

이제 TypeScript 4.5는 템플릿 문자열 유형이 있는 값을 좁힐 수 있으며 템플릿 문자열 유형을 판별 요소로 인식할 수 있습니다.

예를 들어, 이전에는 다음 항목이 실패했지만 이제는 TypeScript 4.5에서 유형 검사에 성공했습니다.

export interface Success {
    type: `${string}Success`;
    body: string;
}
 
export interface Error {
    type: `${string}Error`;
    message: string
}
 
export function handler(r: Success | Error) {
    if (r.type === "HttpSuccess") {
        const token = r.body;
                     
(parameter) r: Success
    }
}

TypeScript는 무한 재귀 또는 유형 확장을 탐지할 때 시간이 오래 걸리고 편집기 환경에 영향을 줄 수 있는 경우 정상적으로 실패해야 하는 경우가 많습니다.

 

이제 타입스크립트는 es.2022를 지원합니다. es.2022의 특징은 async 밖에서도 await를 사용할 수 있다는 점입니다.

Tail-Recursion Elimination on Conditional Types

타입스크립트는 무한 재귀 또는 오랜시간이 걸리는 작업에 대해서 정상적으로 실패해야하는 경우가 종종 있습니다.

결과적으로 타입스크립트는 휴리트릭스(시간이나 정보가 충분하지 않아 합리적인 판단을 할 수 없을 때, 혹은 굳이 합리적 판단을 할 필요가 없을 때 신속하게 사용하는 어림짐작)를 가지고 있다. 무한히 깊은 영역을 선택할 때

 

type InfiniteBox<T> = { item: InfiniteBox<T> };
type Unpack<T> = T extends { item: infer U } ? Unpack<U> : T;
// error: Type instantiation is excessively deep and possibly infinite.
type Test = Unpack<InfiniteBox<number>>;

위 예제는 간단하고 유용하다. 하지만 더 풍부한 휴리트릭스가 있다. 예를 들어 다음 TrimLeft 타입은 문자열 타입의 빈칸을 지웁니다.

type TrimLeft<T extends string> =
    T extends ` ${infer Rest}` ? TrimLeft<Rest> : T;
// Test = "hello" | "world"
type Test = TrimLeft<"   hello" | " world">;

이 유형은 유용할 수 있지만 문자열에 공백이 50개 있으면 오류가 발생합니다.

type TrimLeft<T extends string> =
    T extends ` ${infer Rest}` ? TrimLeft<Rest> : T;
// error: Type instantiation is excessively deep and possibly infinite.
type Test = TrimLeft<"                                                oops">;

하지만 구원의 은총이 있습니다. TrimLeft는 한 분기에서 tail-recursive 방식으로 작성되었습니다. 자신을 다시 호출하면 즉시 결과를 반환하고 아무 작업도 하지 않습니다. 이러한 유형은 중간 결과를 생성할 필요가 없기 때문에 TypeScript에 내장된 많은 유형의 재귀 휴리스틱을 트리거하지 않는 방식으로 더 빠르게 구현할 수 있습니다. 이것이 TypeScript 4.5가 조건부 타입에 대해 일부 tail-recursion 제거를 수행하는 이유입니다. 조건부 타입의 한 분기가 단순히 다른 조건부 유형인 한 TypeScript는 중간 인스턴스화를 피할 수 있습니다. 

 

type GetChars<S> =
    S extends `${infer Char}${infer Rest}` ? Char | GetChars<Rest> : never;

만약 당신이 tail-recursive를 사용하고 싶다면 tail-recursion 함수와 마찬가지로 "accumulator"타입 매개 변수를 사용하는 도우미를 소개할 수 있습니다.

type GetChars<S> = GetCharsHelper<S, never>;
type GetCharsHelper<S, Acc> =
    S extends `${infer Char}${infer Rest}` ? GetCharsHelper<Rest, Char | Acc> : Acc;

더 많은 정보를 확인할 수 있습니다 here.

type Reverse<T> = any[] extends T ? T : ReverseRec<T, []>;
type ReverseRec<T, Acc extends unknown[]> =
    T extends [infer Head, ...infer Tail] ? ReverseRec<Tail, [Head, ...Acc]> : Acc;

type T1 = Reverse<[0]>; // [0]
type T3 = Reverse<1>; // []
type T4 = Reverse<'1'>; // []

type TupleOf<T, N extends number> = number extends N ? T[] : TupleOfRec<T, N, []>;

type TupleOfRec<T, N extends number, Acc extends unknown[]> =
    Acc["length"] extends N ? Acc : TupleOfRec<T, N, [T, ...Acc]>;

type T2 = TupleOf<any, 2>; // [any, any]

Disabling Import Elision

타입스크립트가 import 감지할 수 없는 경우가 있습니다. 

import { Animal } from "./animal.js";
eval("console.log(new Animal().isDangerous())");

기본적으로 TypeScript는 이 import기를 사용하지 않는 것으로 표시되므로 항상 제거합니다. TypeScript 4.5에서는 preserveValueImports라는 새 플래그를 사용하도록 설정하여 TypeScript가 JavaScript 출력에서 가져온 값을 제거하지 못하도록 할 수 있습니다. eval을 사용해야 하는 타당한 이유는 거의 없지만, 이와 유사한 일이 Svelte에서 발생합니다.

<!-- A .svelte File -->
<script>
  import { someFunc } from "./some-module.js";
</script>
<button on:click="{someFunc}">Click me!</button>

Vue.js에서 기능을 사용하여 다음을 수행합니다.

<!-- A .vue File -->
<script setup>
  import { someFunc } from "./some-module.js";
</script>
<button @click="someFunc">Click me!</button>

이러한 프레임워크는 그들의 태그 외부의 마크업을 기반으로 일부 코드를 생성하지만, TypeScript는 오직 태그 내의 코드만 본다. 이것은 TypeScript가 자동으로 일부 Func의 가져오기를 중지하고 위의 코드를 실행할 수 없다는 것을 의미합니다! TypeScript 4.5에서는 preserveValueImports를 사용하여 이러한 상황을 방지할 수 있습니다.

이 플래그는 -isolated Modules'와 결합할 때 특별한 요구 사항이 있습니다. 한 번에 단일 파일을 처리하는 컴파일러는 가져오기가 사용되지 않는 것으로 보이는 값인지 아니면 런타임 충돌을 피하기 위해 제거해야 하는 유형인지 알 수 없기 때문에 type은 type-only로 표시되어야 한다.

// Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,
// ts-loader, esbuild, etc. don't, so `isolatedModules` gives an error.
import { someFunc, BaseType } from "./some-module.js";
//                 ^^^^^^^^
// Error: 'BaseType' is a type and must be imported using a type-only import
// when 'preserveValueImports' and 'isolatedModules' are both enabled.

typeModifiers on Import Names

위에서 언급한 바와 가이  preserveValueImports 와 isolatedModules에는 특별한 요구 사항이 있어드롭 유형 가져오기가 안전한지 여부에 따라 빌드 도구에 애매함이 없습니다.

 

// Which of these is a value that should be preserved? tsc knows, but `ts.transpileModule`,
// ts-loader, esbuild, etc. don't, so `isolatedModules` issues an error.
import { someFunc, BaseType } from "./some-module.js";
//                 ^^^^^^^^
// Error: 'BaseType' is a type and must be imported using a type-only import
// when 'preserveValueImports' and 'isolatedModules' are both enabled.

이러한 옵션이 결합되면 우리는 import가 합법적으로 삭제할 수 있을 때 신호를 보낼 방법이 필요합니다. 

import type { BaseType } from "./some-module.js";
import { someFunc } from "./some-module.js";
export class Thing implements BaseType {
  // ...
  }

작동은 되지만 동일한 모듈에서 두 개의 import를 하는 것을 좋지 않습니다.

import { someFunc, type BaseType } from "./some-module.js";
export class Thing implements BaseType {
    someMethod() {
        someFunc();
    }
}

위의 예에서 BaseType은 항상 지워지는 것이 보장되고 someFunc는 reservedValueImports 아래에 보존되므로 다음 코드가 남습니다.

import { someFunc } from "./some-module.js";
export class Thing {
  someMethod() {
    someFunc();
  }
}

Private Field Presence Checks

TypeScript 4.5는 개체에 개인 필드가 있는지 여부를 확인하기 위한 ECMAScript 제안을 지원합니다. 이제 #private 필드 멤버가 있는 클래스를 작성하고 in 연산자를 사용하여 다른 개체에 동일한 필드가 있는지 확인할 수 있습니다.

Import Assertions

TypeScript 4.5는 import assertion을 위한 ECMAScript 제안을 지원합니다. 이것은 가져오기가 예상 형식인지 확인하기 위해 런타임에서 사용하는 구문입니다.

import obj from "./something.json" assert { type: "json" };

이러한 어설션의 내용은 호스트별로 다르기 때문에 TypeScript에서 확인하지 않으며 브라우저와 런타임에서 처리할 수 있도록(및 오류 가능성도 있음) 단순히 남겨둡니다.

// TypeScript is fine with this.
// But your browser? Probably not.
import obj from "./something.json" assert {
    type: "fluffy bunny"
};

동적 import() 호출은 두 번째 인수를 통해 가져오기 주장을 사용할 수도 있습니다.

const obj = await import("./something.json", {
  assert: { type: "json" },
});

두 번째 인수의 예상 유형은 ImportCallOptions라는 새로운 유형으로 정의되며 현재는 assert 속성만 허용합니다.

Faster Load Time withrealPathSync.native

TypeScript는 이제 모든 운영 체제에서 Node.js realPathSync 함수의 시스템 구현을 활용합니다.

이전에는 리눅스에서만 사용되었지만, 타입스크립트 4.5에서는 일반적으로 대소문자를 구분하지 않는 운영 체제(예: 윈도우, 맥 OS)에 채택되었다. 특정 코드 기반에서 이러한 변경으로 프로젝트 로딩 속도가 5-13% 빨라졌습니다.(호스트 운영 체제에 따라 다름)

Snippet Completions for JSX Attributes

TypeScript 4.5는 JSX 속성에 대한 코드 조각 완료를 제공합니다. JSX 태그에 속성을 쓸 때 TypeScript는 이미 해당 속성에 대한 제안을 제공하지만, snippet이 완료되면 이니셜라이저를 추가하고 커서를 올바른 위치에 놓음으로써 약간의 추가 입력을 제거할 수 있습니다.

 

타입스크립트는 일반적으로 initializer에 삽입하기 위해 타입을 추론을합니다. 그러나 Visual Studio Code에서 이 행동을 사용자 지정할 수 있습니다.

 

이 기능은 최신 버전의 Visual Studio Code에서만 작동하므로 이 기능을 사용하려면 Insiders 빌드를 사용해야 할 수도 있습니다. For more information, read up on the original pull request

 

Added Jsx Snippet Completion feature by armanio123 · Pull Request #45903 · microsoft/TypeScript

Implements suggestion #38891.

github.com

Better Editor Support for Unresolved Types

때때로, editor는 활용할 것입니다. 가벼운 "partial" semantic mode - editor가 전체 프로젝트가 로드되기를 기다리는 동안 또는 GitHub의 웹 기반 편집기와 같은 컨텍스트에서.

TypeScript의 이전 버전에서는 언어 서비스가 타입을 찾을 수 없으면 any를 나타냅니다.

위의 예에서 Buffer를 찾을 수 없었기 때문에 TypeScript는 이를 any로 대체했습니다. TypeScript 4.5에서 TypeScript는 사용자가 작성한 내용을 보존하기 위해 최선을 다할 것입니다.

그러나 Buffer 자체에 마우스를 가져가면 TypeScript가 Buffer를 찾을 수 없다는 힌트를 얻을 수 있습니다.

잘못 해석된 부분이 있다고 생각되시면 댓글 남겨주세요.

 

728x90

'프론트엔드 > Typescript' 카테고리의 다른 글

TypeScript에서의 캡슐화와 추상화  (0) 2022.04.16
TypeScript란?  (0) 2021.08.29