TypeScript How to set a default value with Interface

eye-catch JavaScript/TypeScript

Interface is a powerful feature supported by many programming languages. However, if we want to set a default value, we need to set it one property by one property.

Is there any good alternative instead of assigning a value one by one?

Sponsored links

Repeating the change if setting a default value one by one

Normal way to set a default value to a property is the following.

interface MyInterface {
    a: number;
    b: string;
    c: unknown;
}

const data1: MyInterface = {
    a: 0,
    b: "default-string",
    c: "something",
};
const data2: MyInterface = {
    a: 0,
    b: "default-string",
    c: { value: 1 },
};

Property a and b are the default value. Only property c is the difference. If we need to change the default value, we have to change two places. If we have many objects to be updated, we might forget to update one of them.
Likewise, when we add additional properties, we need to add them to multiple places.

This is what we need to improve.

Sponsored links

Prepare an object that has default value set

Using Spread Operator

If we can copy the default value to the target object, it’s easy to reuse it by using a spread operator.

const MyInterfaceDefault: MyInterface = {
    a: 0,
    b: "default-string",
    c: null,
};
const data1: MyInterface = {
    ...MyInterfaceDefault,
    c: "something",
};
const data2: MyInterface = {
    ...MyInterfaceDefault,
    c: { value: 1 },
};
console.log(data1);
// { a: 0, b: 'default-string', c: 'something' }
console.log(data2);
// { a: 0, b: 'default-string', c: { value: 1 } }

Please check the following article if you still don’t know about the three dots called spread operator.

As you can see, both objects have the same value for properties a and b.

Prepare a function that set the default value

You might even think that it is cumbersome to use a spread operator for each object creation. If you think so, preparing a function is an alternative.

function createMyInterface(options?: Partial<MyInterface>): MyInterface {
    const defaultValue: MyInterface = {
        a: 0,
        b: "default-string",
        c: null,
    };
    return {
        ...defaultValue,
        ...options,
    }
}

console.log(createMyInterface());
// { a: 0, b: 'default-string', c: null }
console.log(createMyInterface({ a: 999, c: "set-my-string" }));
// { a: 999, b: 'default-string', c: 'set-my-string' }

You don’t have to use the spread operator for each object creation. It is easier to create an object.

Default value with a class definition that implements an interface

What if we use an interface for a class definition?

class MyClass implements MyInterface {
    public a: number = 22;
    public b: string = "I'm good";
    public c: unknown = { value: 55 };
}

Do we always need to set it like this?

For a class definition, we can instead extend a class. Let’s define a base class then.

class MyInterfaceBase implements MyInterface {
    public a: number = 22;
    public b: string = "I'm good";
    public c: unknown = { value: 55 };
}
const instance = new MyInterfaceBase();
console.log(instance.a); // 22
console.log(instance.b); // I'm good
console.log(instance.c); // { value: 55 }

Once we create the base class, we can extend it for our desired class.

class ExtendedMyClass extends MyInterfaceBase { }
const instance = new ExtendedMyClass();
console.log(instance);
// ExtendedMyClass { a: 22, b: "I'm good", c: { value: 55 } }

If the class doesn’t have to have additional properties, define the class with extends keyword without having anything in the class.

If you need additional properties, you can of course write in the following way.

class ExtendedMyClass2 extends MyInterfaceBase {
    public d: number = 1234567890;
}
const instance2 = new ExtendedMyClass2();
console.log(instance2);
// ExtendedMyClass2 {
//   a: 22,
//   b: "I'm good",
//   c: { value: 55 },
//   d: 1234567890
// }

Related articles

Comments

Copied title and URL