2

Suppose you have a very large object defined as a TypeScript interface:

interface AccountInterface {
  accountIdentifier?: string;
  sid?: string;
  idToken?: {
    aio?: string;
  };
  idTokenClaims?: {
      aio?: string;
  };
}

I would like the object to always have its properties and sub properties. They can either be a string or an empty string:

let account = {
  accountIdentifier: "",
  sid: "",
  idToken: {
    aio: "",
  },
  idTokenClaims: {
    aio: "",
  },
};

Reading the other questions I thought it would have been possible to do this:

const emptyAccount = {} as AccountInterface

console.log('emptyAccount ', emptyAccount)
console.log('emptyAccount.sid ', emptyAccount.sid)

But this doesn't create an object with all the properties as empty strings as desired.

It would be great if something like this would be possible, so there's no need to duplicate the object in the code, as in one for the interface and one for the object with empty string properties.

3
  • 1
    I don't think there's a "default value that matches interface" feature in typescript and I also don't see any sensible way of providing one automatically. Why would an empty string be default? If the type is string|number|null then what would be the default. If the value is optional (which in your case they all are) is the default undefined or the default of the type if it would exist and if so why is it optional then? Commented May 8, 2020 at 12:04
  • "Reading the other questions" - which ones? Please link them. Commented May 8, 2020 at 12:04
  • I'm new to TS so still learning here. Updated the question. Commented May 8, 2020 at 12:05

2 Answers 2

4

You can create a class that implements that interface, adding the default values, and use that to create your objects. You are still re-writing the same structure elsewhere, but now you only have to do it one time, and you could use the constructor to initialize your object with different values if you want.

interface AccountInterface {
  accountIdentifier?: string;
  sid?: string;
  idToken?: {
      aio?: string;
  };
  idTokenClaims?: {
      aio?: string;
  };
}

class Account implements AccountInterface {
  accountIdentifier = '';
  sid = '';
  idToken = { aio: '' };
  idTokenClaims = { aio: '' };
}

const emptyAccount = new Account();

Also, as pointed out by @apokryfos, you can also use the class to type objects, so there's no need to define both an instance and a class unless you are going to have objects implementing that instance that haven't been created using the class (as those would not have the methods defined in the class).

If you want to avoid using class and use a function to do something similar, you totally can:

function createAccount(): AccountInterface {
  return {
    accountIdentifier = '';
    sid = '';
    idToken = { aio: '' };
    idTokenClaims = { aio: '' };
  };
}

const emptyAccount = createAccount();
Sign up to request clarification or add additional context in comments.

7 Comments

You don't even need to have the interface at all. You can declare the types in the class and then TypeScript is very happy to use the class both as a type and as a value depending on context
Can it be done without a class? I'd like to use functions ir possible.
Yes, that's right. I'm just assuming the interface is going to be there anyway for some reason. Maybe you might have objects with those properties that are not instances of the class.
The goal was actually to avoid having to type out 2 times the object properties. That's why I wanted to instantiate the object from the interface without typing it all out again.
Check! Thank you :) I just thought this would've been possible without retyping the property names. Closing this one then, thanks again to all for the help.
|
0

const emptyAccount = {} as AccountInterface should create an object. But your AccountInterface only includes properties which may exist but must not (because of the ?). So an empty object completely matches your AccountInterface.

If you want to have a property with a default value to be included then you will have to declare it in your interface.

interface AccountInterface {
    accountIdentifier: string|null // <- will be included in {} as AccountInterface
    sid?: string // <- will not be included in {} as AccountInterface
}

1 Comment

the emptyAccount object is still not having the property accountIdentifier, even when taking away all the question marks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.