prosource

Promise의 종류를 개봉하는 방법

probook 2023. 2. 27. 22:27
반응형

Promise의 종류를 개봉하는 방법

다음과 같은 코드가 있다고 가정합니다.

async promiseOne() {
  return 1
} // => Promise<number>

const promisedOne = promiseOne()

typeof promisedOne // => Promised<number>

약속 결과의 유형(이 단순화된 경우 숫자)을 고유한 유형으로 추출하려면 어떻게 해야 합니까?

타입 스크립트 4.5

Awaited이제 type이 언어에 내장되어 있으므로 사용자가 직접 작성할 필요가 없습니다.

type T = Awaited<Promise<PromiseLike<number>> // => number

TypeScript 4.1 ~4.4

몇 가지 가능한 정의를 사용하여 직접 구현할 수 있습니다.가장 간단한 것은 다음과 같습니다.

type Awaited<T> = T extends PromiseLike<infer U> ? U : T
// Awaited<Promise<number>> = number

에서는, 「」가 사용되고 있는 해 주세요.PromiseLikePromise사용자 정의 대기 가능 개체를 적절하게 처리하려면 이 작업이 중요합니다.

이것은 조건부 유형을 사용하여 다음 중 하나를 확인합니다.T약속처럼 보이고, 만약 있다면 개봉하세요. 처리됩니다.Promise<Promise<string>>Promise<string>약속을 기다리는 것은 두 번째 약속을 할 수 없기 때문에 더 좋은 정의는 반복적으로 약속을 푸는 것입니다.

type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T
// Awaited<Promise<Promise<number>>> = number

TypeScript 4.5(소스)에서 사용되는 정의는 대부분의 사용 사례에 적용되지 않는 엣지 케이스를 다루는 데 이보다 더 복잡하지만 모든 TypeScript 4.1+ 프로젝트에 드롭할 수 있습니다.

TypeScript 2.8 ~ 4.0

TypeScript 4.1 이전 버전에서는 재귀형 에일리어스를 의도적으로 지원하지 않았습니다.위의 간단한 버전은 계속 작동하지만, 재귀 솔루션에서는 컴파일러가 재귀적이지 않다고 속이고 인덱스 액세스 유형으로 원하는 속성을 끌어내기 위해 추가 개체 유형이 필요합니다.

type Awaited<T> = T extends PromiseLike<infer U>
  ? { 0: Awaited<U>; 1: U }[U extends PromiseLike<any> ? 0 : 1]
  : T

이것은 공식적으로는 지원되지 않지만 실제로는 전혀 문제가 없습니다.

TypeScript 2.8 이전 버전

TypeScript 2.8 이전 버전에서는 이 작업을 직접 수행할 수 없습니다.2.8에서 도입된 조건부 타입 없이 약속과 같은 타입을 언랩하려면 오브젝트에서 범용 타입을 사용할 수 있어야 합니다.이것에 의해, 인덱스의 액세스 타입을 사용해 값을 취득할 수 있습니다.

이 유형의 범위를 단일 수준의 약속으로 제한하고 약속만 수락하면 선언 병합을 사용하여 글로벌에 속성을 추가하는 방법으로 2.8에서 이를 수행할 수 있습니다.Promise<T>인터페이스입니다.

interface Promise<T> {
    __promiseValue: T
}
type Awaited<T extends Promise<any>> = T["__promiseValue"]

type T = Awaited<Promise<string>> // => string

우선 TypeScript 4.1 릴리즈 노트에는 다음과 같은 스니펫이 있습니다.

type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;

해서 문제를 할 수 .const x = (url: string) => fetch(url).then(x => x.json())그러나 Jon Jaques의 답변과 ErikE의 코멘트를 조합하여 4.1보다 오래된 버전을 사용하고 있는 것을 고려하면 다음과 같습니다.

type Await<T> = T extends PromiseLike<infer U> ? U : T

및 예:

const testPromise = async () => 42
type t1 = Await<ReturnType<typeof testPromise>>
// t1 => number

갱신하다

TypeScript 4.5부터는 TmTron이 답변한 대로 키워드를 사용할 수 있게 되었습니다.

소스 코드를 확인해 보시기 바랍니다.소스코드는 재귀적이고 매우 흥미로운 엣지 케이스가 몇 가지 있습니다.이 케이스는 제 솔루션에서는 검출되지 않았습니다.

원래의

오래된 질문이지만, 제 2센트를 더하고 싶습니다.를 사용하여 약속의 포장을 해제하다Promise타입은 편리하지만, 내가 발견한 것은 내가 보통 "그때" 객체의 가치를 알아내는 것에 관심이 있었다는 것이다. 예를 들어, 어떤 물건과 같은await오퍼레이터가 합니다.

이걸 위해서 제가 쓴 게Await<T>helper: 약속과 그 후의 오브젝트를 언랩합니다.

type Await<T> = T extends {
    then(onfulfilled?: (value: infer U) => unknown): unknown;
} ? U : T;

다음과 같이 사용합니다.

const testPromise = async () => 42
type t1 = Await<ReturnType<typeof testPromise>>
// t1 => number

업데이트(typescript > = 4.5)

타이프 스크립트 4.5를 사용할 수 있습니다.Awaited: "Typescript 릴리즈 노트" 참조

const promise = new Promise<string>((res, rej) => res('x'))    
type test0 = Awaited<typeof promise>  // string
type test1 = Awaited<Promise<number>> // number

Stackblitz의 예

원래의

ts-toolbelt lib에는 Promise가 있습니다.

import {C} from 'ts-toolbelt'

const promise = new Promise<string>((res, rej) => res('x'))    
type test0 = C.PromiseOf<typeof promise>  // string
type test1 = C.PromiseOf<Promise<number>> // number

사용할 수 있습니다.type-festnpm 모듈에 액세스할 수 있는 경우:

import {PromiseValue} from 'type-fest';

async promiseOne() {
  return 1
} // => () => Promise<number>

PromiseValue<promiseOne()>
//=> number

이 기능을 실장할 예정인 타입스크립트 3.9.아쉽게도 이전 버전인 4.0 버전이 될 것 같습니다.

새로운 유형은 다음과 같이 불릴 것입니다.awaited하위 호환성 문제로 인해 지연되었습니다.

GitHub 관련 토론.

Promise의 파라미터를 확인할 수 있습니다.then유형을 추론하는 기능.

type PromisedString = Promise<string>;
type AwaitedPromisedString = Parameters<Parameters<PromisedString['then']>[0] & {}>[0];

const promisedString: PromisedString = Promise.resolve('sup');
const x: AwaitedPromisedString = await promisedString;
// assignment succeeds!
const y: string = x;

유틸리티 유형으로 일반화할 수 있습니다.

type Awaited<T extends Promise<unknown>> = Parameters<Parameters<T['then']>[0] & {}>[0];
const promisedString: Promise<string> = Promise.resolve('sup');
const x: Awaited<typeof promisedString> = await promisedString;
const y: string = x;

이 점에 대해 설명하겠습니다.

Promise<string>['then']콜백을 받아들이는 함수.그 함수의 파라미터를 구합시다.
Parameters<Promise<string>['then']>[0]첫 번째 파라미터then: 콜백입니다.이것은 선택 사항이기 때문에, 끈적끈적한 유형으로만 결합을 좁혀야 합니다.
Parameters<Promise<string>['then']>[0] & {}콜백 자체입니다.함수입니다. 그 매개변수를 잡읍시다.
Parameters<Parameters<Promise<string>['then']>[0] & {}>[0]콜백의 첫 번째 파라미터: Promise에 의해 해결되는 값.이게 우리가 찾던 거야

위의 조건 타입에 비추어 보면 이 답변은 중복되어 보일 수 있지만, JSDoc 내에서 새로운 유틸리티 타입을 정의할 수 없지만 기존 유틸리티 타입을 사용할 수 있는 Promise를 해결하는 방법은 다음과 같습니다.

/** @param {Parameters<Parameters<ReturnType<import('box2d-wasm')>['then']>[0] & {}>[0]} box2D */
export const demo = box2D => {
};

다음 두 단계로 진행됩니다.

// First, define a type for async functions returning V
type AsyncFunction<V> = (...args: never[]) => PromiseLike<V>

// Second, use the AsyncFunction + infer to define AsyncReturnType
type AsyncReturnType<V> = V extends AsyncFunction<infer U> ? U : V

이 경우 다음 작업을 수행할 수 있습니다.

let foo: AsyncReturnType<typeof promiseOne>

이 명령어를 사용하는 경우AsyncReturnType내보낼 필요가 없습니다.AsyncFunction.그...args이다never당신이 그들을 무시하고 있으니까.

이 답변은 Evan의 답변과 유사합니다. 이 답변은 변경은 원치 않지만 추가 정보는 제거해 줍니다.<ReturnType>★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

언급URL : https://stackoverflow.com/questions/48011353/how-to-unwrap-the-type-of-a-promise

반응형