Defaulting Unspecified Interface Properties to Null in TypeScript

I have the following TypeScript interface:

interface IX {
    a: string;
    b: any;
    c: AnotherType;
}

I declare a variable of this type and initialize all the properties with default values:

let x: IX = {
    a: 'abc',
    b: null,
    c: null
};

Later, I assign actual values to these properties in an init function:

x.a = 'xyz';
x.b = 123;
x.c = new AnotherType();

I don’t like having to specify default null values for each property when declaring the object, especially since they will be set to real values later. Is there a way to have TypeScript default unspecified properties to null when using an interface, so I can initialize the object like this:

let x: IX = {
    a: 'abc'
};

without receiving a compiler error? Currently, I’m getting the error: TS2322: Type ‘{}’ is not assignable to type ‘IX’. Property ‘b’ is missing in type ‘{}’.

No, you cannot set default values for properties in TypeScript interfaces or type aliases, as they are purely compile-time constructs and do not support runtime default values.

However, in JavaScript, properties that are not explicitly set default to undefined. You can make properties optional in your interface to accommodate this:

interface IX {

a: string;

b?: any;

c?: AnotherType;

}

With this setup, you can initialize the object with only the required properties:

let x: IX = {

a: 'abc'

};

You can then assign values to the properties as needed:


x.a = 'xyz';

x.b = 123;

x.c = new AnotherType();

This approach helps with your concern about setting default values while leveraging TypeScript’s flexibility.

Building on Priyanka’s point, another solution is to use a factory method that returns an object implementing the IX interface. This method can help manage default values more cleanly.

Here’s an example:

class AnotherType {}

interface IX {
    a: string;
    b: any;
    c: AnotherType | null;
}

function createIX(): IX {
    return {
        a: 'abc',
        b: null,
        c: null
    };
}

const x = createIX();

x.a = 'xyz';
x.b = 123;
x.c = new AnotherType();

In this approach, the factory method createIX initializes the object with default values. The key change in the interface is making the c property AnotherType | null to avoid compiler errors when initializing it with null. This method effectively manages TypeScript interface default values, making your code cleaner and more maintainable.

Adding to the previous answers, I found an approach that suits my needs better while setting up a new interface, and I think it’s worth sharing. The goal was to write minimal code each time I set up an interface. Here’s what I settled on:

Create a custom generic deepCopy function:

const deepCopy = <T extends {}>(input: any): T => {
  return JSON.parse(JSON.stringify(input));
};

Define your interface:

interface IX {
  a: string;
  b: any;
  c: AnotherType;
}

Define default values in a separate constant:

const XDef: IX = {
  a: '',
  b: null,
  c: null,
};

Initialize your object with default values using deepCopy:

let x: IX = deepCopy(XDef);

For custom initialization, modify the deepCopy function to accept custom default values:

const deepCopyAssign = <T extends {}>(input: any, rootOverwrites?: any): T => {
  return JSON.parse(JSON.stringify({ ...input, ...rootOverwrites }));
};

You can then initialize with custom values like this:

let x: IX = deepCopyAssign(XDef, { a: 'customInitValue' });

Additional Notes:

  • Shallow Copy Alternative: If you only need a shallow copy, Object.assign can be used:
let x: IX = Object.assign({}, XDef, { a: 'customInitValue' });
  • Known Issues: deepCopy and deepCopyAssign use JSON.parse and JSON.stringify, so they won’t handle functions and references, which might be a limitation depending on your use case. Custom initialization values are not type-checked or hinted by the IDE.

This approach allows for easy setup of TypeScript interface default values while providing flexibility for customization.