Issue
I have a type in typescript, that is an object, for which all of the properties should be of type number
. Based on this type, I would like to create various interfaces, which are more concrete then the original type, and pass them as generic parameters to a class, which excepts a generic that extends my basic type, but I always get the following typescript error:
Index signature for type 'xxx' is missing in type 'yyy'
Is something similar to what I want to do is possible in typescript? The best I was able to achieve, is telling my moreConcrete
interface, that it extends the basic
type, this way, the error goes away, but I lose autocompletion and other intellisense features when trying to use the interface.
Here's a fiddle with an example: Fiddle
And here's the code in the fiddle:
type basic = {
[key: string]: number
}
class A<TInput extends basic> {
}
interface moreConcrete {
a: number,
b: number
}
const test = new A<moreConcrete>(); // this does not work like this
interface otherMoreConcrete extends basic {
a: number,
b: number
}
const test2 = new A<otherMoreConcrete>(); // this does not give any errors
const typeTest: keyof otherMoreConcrete = 'as'; // this accepts as as a key of otherMoreConcrete, because of the extension to `basic`, this should be an error
Solution
In order to better understand this problem, please see this answer.
TL;TR
interfaces
have no indexing by the default, whereas types
have.
In order to get rid of an error, just use type
instead of interface
. I mean, instead of using:
interface moreConcrete {
a: number,
b: number
}
use
type moreConcrete= {
a: number,
b: number
}
const test = new A<moreConcrete>(); // ok
You can find extra examples in my article
Is this super safe to use type
instead of interface
? I don't think so. It all depends on your code and what you want to achieve. I'm not aware of all edge cases. So, it should be thoroughly tested.
It might be safe to use type
instead of interface
in this particular case because A
class expects indexed type.
As for the second problem:
interface otherMoreConcrete extends basic {
a: number,
b: number
}
const test2 = new A<otherMoreConcrete>(); // this does not give any errors
const typeTest: keyof otherMoreConcrete = 'as'; // this accepts as as a key of otherMoreConcrete, because of the extension to `basic`, this should be an error
You don't have error here, because there is a big difference between otherMoreConcrete
interface and moreConcrete
. otherMoreConcrete
extends basic
. It means that it has indexed property. I mean apart from having a
and b
it accepts any string key.
type otherMoreConcrete = {
[x: string]: string;
a: "a";
b: "b";
}
Hence, if you want to trigger en error in your last example, just use type
instead of interface
:
type basic = {
[key: string]: number
}
class A<TInput extends basic> {}
type moreConcrete = {
a: number,
b: number
}
const test = new A<moreConcrete>(); // ok
type otherMoreConcrete = {
a: number,
b: number
}
const test2 = new A<otherMoreConcrete>(); // ok
const typeTest: keyof otherMoreConcrete = 'as'; // error
Answered By - captain-yossarian
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.