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.