Search code examples
typescripttypes

Is it possible to make all optional properties of typescript interface accept null?


I have a interface defined as

interface IExample {
  property1: string;
  property2: number;
  property3?: number;
  property4?: string;
}

How do I make all optional properties accept null? I don't want to add null to each optional property

I tried creating this type but this this does not work

  type SetOptionalKeysNullable<T> = {
    [K in keyof T]: T[K] extends undefined ? undefined | null : T[K];
  };


Solution

  • The best way to detect optional properties is to use the (unsafe but convenient) assignability of a missing property to an optional property to a missing property. That is, {} is assignable to {a?: string}, but not to {a: string} or to {a: string | undefined}. Any checking that just looks at undefined will end up being unable to distinguish optional properties from required properties that expect undefined. So for each property K in keyof T, if {} is assignable to Pick<T, K>, then K is optional in T:

    type SetOptionalKeysNullable<T> = {
      [K in keyof T]: T[K] | ({} extends Pick<T, K> ? null : never)
    };
    

    Let's test it out:

    interface IExample {
      property1: string;
      property2: number;
      property3?: number;
      property4?: string;
    }    
    type ExOut = SetOptionalKeysNullable<IExample>;
    /* type ExOut = {
        property1: string;
        property2: number;
        property3?: number | null | undefined;
        property4?: string | null | undefined;
    } */
    
    // none of these properties are optional
    type Also = SetOptionalKeysNullable<{
      a: string; 
      b: string | null;
      c: string | undefined;
    }>
    type AlsoOut = SetOptionalKeysNullable<Also>;
    /* type AlsoOut = {
        a: string;
        b: string | null;
        c: string | undefined;
    } */
    

    Looks good. All of the optional properties get null added to their domain, whereas nothing happens to any of the required properties.

    Playground link to code