2

I am trying to extends some properties from another object:

interface IAlice {
  foo: string;
  bar: string;
};

interface IBob extends IAlice {
  aFunction(): number;
  anotherValue: number;
};

let alice: IAlice = {
  foo: 'hi',
  bar: 'bye'
};

let bob: IBob = Object.assign({}, alice); // Typescript error no aFunction & anotherValue

bob.anotherValue = 2;
bob.aFunction = (): number => {
  return 3;
}

As you can see typescript returns a error.

I know a plausible workaround is to make bob values optional, but that isn't solving the problem. Or assigning values inside Object.assign doesn't work either because there's a function.

Is there anyway to let typescript recognize that the value are going to be defined?

2
  • Have you try casting ? let bob: IBob = <IBob> Object.assign({}, alice); Commented Aug 17, 2018 at 12:48
  • The real question is why you want alice to be bob? Commented Aug 17, 2018 at 13:38

2 Answers 2

3

If bob is of type IBob it must always have all the fields of IBob defined. The simplest solution is to create the object fully formed as an IBob instance:

let bob: IBob  = Object.assign({
    anotherValue: 2,
    aFunction : (): number => {
        return 3;
    }
}, alice);

If you want the object to be partially initialized and have some fields missing you can use Partial:

let bob: Partial<IBob> = Object.assign({}, alice);

bob.anotherValue = 2;
bob.aFunction = (): number => {
    return 3;
}

This will make all fields optional which might not be apropriate in all circumstances, but it's good to keep Partial in mind as an option.

If you really want to get fancy with your typing, you can even make just the fields of IBob optional while keeping the ones from IAlice mandatory

let bob: Partial<Pick<IBob, Exclude<keyof IBob, keyof IAlice>>> & IAlice = Object.assign({}, alice);

bob.anotherValue = 2;
bob.aFunction = (): number => {
    return 3;
}

The reason it's important to be specific about what is optional and what not is that under strictNullChecks you will not be able to access optional fields unless you explicitly check for null.

The brute force unsafe option is to just use a type assertion to get the assignment to work. I include this for completeness but I would avoid assertions that are not true if possible (you are basically lying to the compiler that the result of Object.assign has all the fields of IBob it does not and the compiler will miss errors that may be caused by those missing fields)

let bob: IBob = Object.assign({}, alice) as IBob;
// Or (but only if you are not in a tsx file)
let bob: IBob = <IBob>Object.assign({}, alice);
Sign up to request clarification or add additional context in comments.

Comments

0

You can do it like this:

let bob: IBob | IAlice = Object.assign({}, alice);

Now both type of objects IBob and IAlice can be assigned to bob.

2 Comments

That does not look like the desired result here, the OP is trying to create an IBob object not something that is either or. And with your code the next lines will not work bob.anotherValue = 2; bob.aFunction = (): number => { return 3; }
Schrödinger would be proud

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.