I am writing an object interface, one of which is an attribute value is a class . But ts compiler will throw an exception when this class extends other classes .
Here is a simple example:
class Base {
key: string
}
class Foo extends Base { }
interface Obj {
list: Foo[]
value: Foo
}
const obj: Obj = {
list: [new Foo()],
value: Foo // < Throws error here
}
The error content:
Property 'key' is missing in type 'typeof Foo' but required in type 'Base'.ts(2741)
test.ts(39, 5): 'key' is declared here.
test.ts(51, 12): Did you mean to use 'new' with this expression?
And when I delete the extends in Foo
, the error disappeared:
class Foo { } // < delete extends here
interface Obj {
list: Foo[]
value: Foo
}
const obj: Obj = {
list: [new Foo()],
value: Foo // < No error throw
}
In my understanding, Foo
extends from Base
, so it should include the relevant attributes in Base
, but the compiler tells me it does not.
So is there any way to solve this problem?
There is another question. When I use generics on Obj
because there are multiple type extends Base
. like this:
class Foo extends Base { }
class Bar extends Base { }
interface Obj<T extends Base> {
list: Foo[]
value: typeof T // < Throws error here
}
const obj: Obj<Foo> = {
list: [new Foo()],
value: Foo
}
compiler will throw an exception as below:
'T' only refers to a type, but is being used as a value here.
Is there a way to make the generic definition a bit more complete?
12.16.1
3.8.3
and 4.3.4
value
in your Obj
interface is an instance of the Foo
class, not the class itself. So assigning an object whose value
property is the Foo
class to a variable of the interface type is an error. You should set value
to an instance of Foo
(such as new Foo()
, which is what the compiler error message suggests), or if you really meant to use Foo
, declare value: typeof Foo
in Obj
.
The reason this works when Foo
does not extend Base
is TypeScript's structural typing: Foo
does not have any properties, so any object, including a class, can be assigned to a variable of that type, even though it may not be an actual instance of Foo
at runtime.
In response to the additional question regarding generics:
typeof T
is not valid when T
is a type parameter, because T
does not have to be a class. It can be an interface that is structurally compatible with Base
, and interfaces do not have an "interface object" whose type can be retrieved with typeof
. You could use this definition of Obj
, which works but requires using typeof
at use sites:
interface Obj<T extends new (...args: any[]) => Base> {
list: Foo[],
value: T
}
const obj: Obj<typeof Foo> = {
list: [new Foo()],
value: Foo
}
key
is a required field in your class Base
. That's why that error. You can either make the property key
optional or write constructors in Base
and Foo
.
Making key
property optional:
class Base {
key?: string
}
class Foo extends Base { }
interface Obj {
list: Foo[]
value: Foo
}
const obj: Obj = {
list: [new Foo()],
value: new Foo()
}
Making key
mandatory property:
class Base {
key: string
constructor(key: string) {
this.key = key;
}
}
class Foo extends Base {
constructor(key: string) {
super(key);
}
}
interface Obj {
list: Foo[]
value: Foo
}
const obj: Obj = {
list: [new Foo()],
value: new Foo()
}
Additionally, the obj
initialization should do new Foo()
for property value
or the type of value
inside Obj
interface should be typeof Foo
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.