У меня есть внутреннее представление модели данных, которое выглядит примерно так:

class InternalDataClass {
    propOne?: Promise<string>;
    propTwo?: Promise<number>;
    propThree?: string;
    ...
}

Некоторые свойства являются Promise, поскольку они заполняются асинхронными процессами. Однако, поскольку это веб-сервис, я хотел бы предоставить эту структуру клиентам в ее проводной форме (очевидно, без обещаний). Нравится:

class ExternalDataClass {
    propOne?: string;
    propTwo?: string;
    propThree?: string;
}

Есть ли простой способ сделать это в Typescript без необходимости заново объявлять все? Это особенно уместно в моем случае, поскольку, да, моя иллюстрация здесь имеет только 3 свойства, но вы можете представить, что класс данных становится значительно больше!

Спасибо! Тим

1
Tim Schmidt 26 Ноя 2019 в 16:40
Связанный? stackoverflow .com / questions / 48944552 /… - UnPromisifiedObject / UnPromisify кажется хорошим кандидатом.
 – 
Caramiriel
26 Ноя 2019 в 16:42
Допустимо ли ExternalDataClass быть псевдонимом типа, а не классом?
 – 
Aleksey L.
26 Ноя 2019 в 16:46
@Caramiriel, это немного отличается, поскольку это включает разворачивание (т.е. полное разрешение) любых свойств Promise объекта. Я действительно делаю нечто подобное в своем веб-сервисе, прежде чем передавать данные по сети. Но я просто искал способ определить тип для использования клиентами. Ответ ниже отлично подходит для этого!
 – 
Tim Schmidt
26 Ноя 2019 в 23:40

1 ответ

Лучший ответ

Вы можете использовать условный тип, чтобы «распаковать» обещание:

class InternalDataClass {
    propOne?: Promise<string>;
    propTwo?: Promise<number>;
    propThree?: string;
}

type UnpackAny<T> = T extends Promise<infer U> ? U: T
type UnpackProperties<T> = {
    [P in keyof T]: UnpackAny<T[P]>
}

type ExtrnalInterface = UnpackProperties<InternalDataClass>
// type ExtrnalInterface = {
//     propOne?: string | undefined;
//     propTwo?: number | undefined;
//     propThree?: string | undefined;
// }

Если вы действительно хотите создать класс, а не просто тип, вы можете принудительно реализовать ExtrnalInterface:

class ExtrnalDataClass extends (class { } as new () => ExtrnalInterface) {

}

Playground Link

2
ethane 26 Ноя 2019 в 21:10
Потрясающие! Я знал, что для этого нужна какая-то уловка с Typescript! Огромное спасибо!
 – 
Tim Schmidt
26 Ноя 2019 в 23:38