0

I want to have a type/interface that includes all properties from a given generic type and adds some more, i. e., that extends it. Also, I want to be able to "downcast" any object of this type to the one it extends.

I will never instantiate any new object of the type that adds the property, since it will only act as a "contract" for an object. Thus, I presume it should never be a class.

So far I've tried to intersect both types, like so:

class MyClass{
   prop1: string;
   prop2: string;

   constructor(){
      this.prop1 = '1';
      this.prop2 = '2';
   }
}

type MyType<T> = T & {
   additionalProp: string;
}

myService.getData()
   .subscribe((res: MyType<MyClass>) => {
      //Do something with res.additionalProp...

      //This one should *not* have "additionalProp" yet it somehow does.
      let anObject: MyClass = <MyClass>res;

      console.log(anObject);
      //output: {prop1: '1', prop2: '2', additionalProp: 'valuefromresponse'}
   });

It may be silly of me, but I've not managed to figure out why anObject in my example still has the property MyType introduces.

To clarify, I'm using generics instead of directly extending MyClass in order to be able to reuse the MyType contract along the code.

2
  • There's no such thing as casting in typescript. <MyClass> is a type assertion and it doesn't affect objects at runtime. All the types are erased at compile time typescriptlang.org/docs/handbook/… Commented Dec 14, 2020 at 11:15
  • You confuse runtime type with declared type. The anObject variable holds the same actual object as res, so no surprise the log shows it. Your cast does not make sense - you mislead typescript about the type of anObject. Commented Dec 14, 2020 at 11:15

1 Answer 1

0

Thanks for your help, @Aleksey L. and @Tomasz Gawel. I've kept MyType the same and opted for adding the following to MyClass:

static fromObject<T extends MyClass>(o: T) {
    return new MyClass(o.prop1, o.prop2);
}

I know it uses static methods and all, but this is the cleanest solution I could come up with. Having this, I can call let anObject: MyClass = MyClass.fromObject(res);, solving both of the problems with my original approach.

Sign up to request clarification or add additional context in comments.

Comments

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.