Я хочу иметь сопоставленный тип, который разрешает обещанные значения.

Этот сопоставленный тип обещает все ключи:

type PromisifiedKeys<T> = { [K in keyof T]: Promise<T[K]> }

Мне нужен сопоставленный тип, который не обещает / разрешает их:

type PromisifiedKeys<T> = { [K in keyof T]: UnPromise<T[K]> }

Я не знаю, как это сделать.

1
Caleb Eby 31 Дек 2017 в 07:17

2 ответа

Лучший ответ

Начиная с Typescript 2.8 есть условные типы. Из справочник:

type Unpacked<T> =
    T extends (infer U)[] ? U :
    T extends (...args: any[]) => infer U ? U :
    T extends Promise<infer U> ? U :
    T;

Пример использования:

const p: Promise<string> = getData();
type ReturnDataType = Unpacked<p>;

Я смог реализовать это как таковое:

interface AsyncSupplementalData {
    couponCodeData: Promise<string>;
}
interface ApplicationState {
    [K in keyof AsyncSupplementalData]: Unpacked< AsyncSupplementalData[K] >
}
2
Adam Mazzarella 30 Июл 2018 в 19:49

Вам действительно нужны сопоставленные условные типы, которых в настоящее время нет в TypeScript.


Есть обходные пути. Если вы хотите испортить глобальную декларацию, of Promise<T> с фантомным свойством, вы можете сделать это:

declare global {
  interface Promise<T> {
    "**unPromise**": T
  }
}
export type UnPromise<T extends Promise<any>> = T['**unPromise**']
export type UnPromisifiedKeys<T extends { [k: string]: Promise<any> }> = 
  {[K in keyof T]: UnPromise<T[K]> }

И вы получите:

type Promised = {
  foo: Promise<string>,
  bar: Promise<number>
}
type UnPromised = UnPromisifiedKeys<Promised>; 
// {foo: string, bar: number}

Это более или менее то, о чем вы просили, но это хакерство.


Или вы можете использовать вывод из сопоставленных типов, чтобы иметь функцию, которая принимает объект типа PromisifiedKeys<T> и возвращает T:

declare function unPromisifyKeys<T>(k: PromisifiedKeys<T>): T;

Это представляет собой функцию того, что вы хотите делать с типами. Если у вас есть конкретные вещи, которые вы хотите передать этой функции, она может быть вам полезна. (То есть, если вы просто искали UnpromisifyKeys<T> как способ представить вывод функции, тогда это решение будет работать как есть). Если вам действительно нужно определить UnpromisifyKeys<T> на уровне типа без конкретного значения T, то вы можете перепрыгнуть через обручи, чтобы компилятор определил правильный тип, не вызывая слишком много загруженной работы во время выполнения:

const unpromised = true as false || unPromisifyKeys(null! as Promised);
type Unpromised = typeof unpromised; 
// {foo: string, bar: number}

Это работает , но некрасиво. Единственное, что есть в первом обходном пути, - это то, что глобальное определение Promise<T> не изменилось.


Может быть, вам подойдет один из этих обходных путей? Надеюсь, это поможет; удачи!

1
jcalz 1 Янв 2018 в 02:19