Tengo una interfaz en mi aplicación:
interface Asset {
id: string;
internal_id: string;
usage: number;
}
que es parte de una interfaz de publicación:
interface Post {
asset: Asset;
}
También tengo una interfaz que es para un borrador de publicación, donde el objeto de activo solo puede construirse parcialmente
interface PostDraft {
asset: Asset;
}
Quiero permitir que un PostDraftobjeto tenga un objeto de activo parcial mientras sigo verificando los tipos en las propiedades que están allí (por lo que no quiero simplemente intercambiarlo any).
Básicamente, quiero una forma de poder generar lo siguiente:
interface AssetDraft {
id?: string;
internal_id?: string;
usage?: number;
}
sin redefinir completamente la Assetinterfaz. ¿Hay alguna forma de hacer esto? Si no es así, ¿cuál sería la forma inteligente de organizar mis tipos en esta situación?
typescript
jkjustjoshing
fuente
fuente

Respuestas:
Esto no es posible en TypeScript <2.1 sin crear una interfaz adicional con propiedades opcionales; sin embargo, esto es posible mediante el uso de tipos asignados en TypeScript 2.1+.
Para hacer esto, use el
Partial<T>tipo que TypeScript proporciona por defecto.interface PostDraft { asset: Partial<Asset>; }Ahora todas las propiedades de
assetson opcionales, lo que le permitirá hacer lo siguiente:const postDraft: PostDraft = { asset: { id: "some-id" } };Acerca de
Partial<T>Partial<T>se define como un tipo mapeado que hace que todas las propiedades en el tipo proporcionado sean opcionales (usando el?token).type Partial<T> = { [P in keyof T]?: T[P]; };Lea más sobre los tipos asignados aquí y en el manual .
fuente
Required<T>).Las propiedades de la interfaz son opcionales, no lo son, no puede usar la misma interfaz una vez como opcional y una vez como debe.
Lo que puede hacer es tener una interfaz con propiedades opcionales para el
AssetDrafty luego una clase con propiedades obligatorias paraAsset:interface AssetDraft { id?: string; internal_id?: string; usage?: number; } class Asset { static DEFAULT_ID = "id"; static DEFAULT_INTERNAL_ID = "internalid"; static DEFAULT_USAGE = 0; id: string; internal_id: string; usage: number; constructor(draft: AssetDraft) { this.id = draft.id || Asset.DEFAULT_ID; this.internal_id = draft.internal_id || Asset.DEFAULT_INTERNAL_ID; this.usage = draft.usage || Asset.DEFAULT_USAGE; } }Los valores predeterminados aquí son miembros estáticos, pero puede obtenerlos de otras formas o lanzar un error en caso de que falten.
Me parece muy cómodo de esta manera cuando trabajo con jsons que se reciben del servidor (o algo similar), las interfaces representan los datos de json y las clases son los modelos reales que se construyen utilizando los jsons como valores iniciales.
fuente
Si quiero tener una
AssetDraftinterfaz explícita , usaría una combinación deextendsyPartial:interface Asset { id: string; internal_id: string; usage: number; } interface AssetDraft extends Partial<Asset> {}fuente
Además de la respuesta de David Sherret, solo unas líneas de mi lado, cómo se puede implementar directamente sin tipografía
Partial<T>para una mejor comprensión del tema.interface IAsset { id: string; internal_id: string; usage: number; } interface IPost { asset: IAsset; } interface IPostDraft { asset: { [K in keyof IAsset]?: IAsset[K] }; } const postDraft: IPostDraft = { asset: { usage: 123 } };fuente
¿Qué tal forzar el lanzamiento de un objeto vacío?
const draft = <PostDraft>{} draft.id = 123 draft.internal_id = 456 draft.usage = 789Si realmente lo necesita, siempre puede generar una interfaz d.ts a partir de una plantilla que haga las propiedades opcionales y escritas.
Como señaló Nitzan, las propiedades de la interfaz de TypeScript son opcionales o no
fuente