1
votes

Here is my code:

interface IOptions {
  clientId: string;
  token: string;
}

interface IComponent {
  name: string;

  parent?: { name: string };
}

async function createComponent(opts?: IOptions): Promise<IComponent> {
  const component: IComponent = { name: '' };

  if (opts) {
    component.parent = { name: `${opts.clientId}-${opts.token}` };
  }

  return component;
}

async function main() {
  const { name, parent } = await createComponent();

  console.log(parent.name);
}

I want to make parent optional property of IComponent interface to required property if the opts is existed in createComponent function.

For now, I got an error when I use parent.name in main function.

Object is possibly 'undefined'.ts(2532)

I want the return value's interface of createComponent function to be like: Promise<IComponentRequired> if opts is existed and return Promise<IComponent> if opts is not existed. which like this:

interface IComponentRequired {
  name: string;

  parent: { name: string };
}

My thinking is IComponent => Required<T> => IComponentRequired.

update

Here is my try, but didn't work.

async function otherMain() {
  const opts: IOptions = { clientId: '123', token: '321' };
  const component: Required<IComponent> = await createComponent(opts);

  console.log(component.parent.name);
}

Got error:

Type 'IComponent' is not assignable to type 'Required'. Types of property 'parent' are incompatible. Type '{ name: string; } | undefined' is not assignable to type '{ name: string; }'. Type 'undefined' is not assignable to type '{ name: string; }'.ts(2322)

1

1 Answers

1
votes

You can use overloads to either return the required version or the one where the property is optional:

interface IOptions {
    clientId: string;
    token: string;
}

interface IComponent {
    name: string;

    parent?: { name: string };
}

async function createComponent(): Promise<IComponent>
async function createComponent(opts: IOptions): Promise<Required<IComponent>>
async function createComponent(opts?: IOptions): Promise<IComponent> {
    const component: IComponent = { name: '' };

    if (opts) {
        component.parent = { name: `${opts.clientId}-${opts.token}` };
    }

    return component;
}

async function main() {
    const opts: IOptions = { clientId: '123', token: '321' };
    const component: Required<IComponent> = await createComponent(opts);

    console.log(component.parent.name);
}