Make all properties within a Typescript interface optional

后端 未结 5 602
离开以前
离开以前 2020-12-12 18:48

I have an interface in my application:

interface Asset {
  id: string;
  internal_id: string;
  usage: number;
}

that is part of a post int

相关标签:
5条回答
  • 2020-12-12 19:06

    The properties in the interface are either optional are not, you can not use the same interface once as optional and once as must.

    What you can do is to have an interface with optional properties for the AssetDraft and then a class with mandatory properties for the Asset:

    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;
        }
    }
    

    The default values here are static members, but you can get those in other ways or throw an error in case they are missing.

    I find this way very comfortable when working with jsons that are received from the server (or something similar), the interfaces represent the json data and the classes are the actual models that are constructed using the jsons as initial values.

    0 讨论(0)
  • 2020-12-12 19:06

    How about force casting an empty object e.g

    const draft = <PostDraft>{}
    draft.id = 123
    draft.internal_id = 456
    draft.usage = 789
    

    If you really really need this then you can always generate a d.ts interface from a template that makes both the optional and typed properties.

    As Nitzan pointed out, either Typescript interface properties are optional or not

    0 讨论(0)
  • 2020-12-12 19:08

    In addition to David Sherret answer just a few lines from my side how it can be implemented directly without Partial<T> type for better understanding of the subject.

    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
      }
    };
    
    0 讨论(0)
  • 2020-12-12 19:25

    This isn't possible in TypeScript < 2.1 without creating an additional interface with optional properties; however, this is possible by using mapped types in TypeScript 2.1+.

    To do this, use the Partial<T> type which TypeScript provides by default.

    interface PostDraft {
        asset: Partial<Asset>;
    }
    

    Now all the properties on asset are optional, which will allow you to do the following:

    const postDraft: PostDraft = {
        asset: {
            id: "some-id"
        }
    };
    

    About Partial<T>

    Partial<T> is defined as a mapped type that makes every property in the provided type optional (using the ? token).

    type Partial<T> = {
        [P in keyof T]?: T[P];
    };
    

    Read more about mapped types here and in the handbook.

    0 讨论(0)
  • 2020-12-12 19:30

    If I want to have an explicit AssetDraft interface, I would use a combination of extends and Partial:

    interface Asset {
      id: string;
      internal_id: string;
      usage: number;
    }
    
    interface AssetDraft extends Partial<Asset> {}
    
    0 讨论(0)
提交回复
热议问题