I have the code below, where I want to pass a request object to an Http Get function
Why does get
accept the object from helperObj
and not the interface Req
from helperInt
Link to Typescript Playground
interface Req {
key: string;
page?: number;
}
function helperInt(req: Req) {
get('', req); // ERROR
// Argument of type 'Req' is not assignable to parameter of type '{ [key: string]: string | number | boolean | (string | number | boolean)[]; }'.
// Index signature for type 'string' is missing in type 'Req'.(2345)
}
function helperObj(req: {
key: string;
page?: number;
}) {
get('', req);
}
function get(url: string, params?: { [key: string]: string | number | boolean | (string | number | boolean)[] }) {
console.log(url, params);
}
const myReq: Req = {
key: "foo",
page: 0,
};
helperInt(myReq);
helperInt({
key: "foo",
page: 0,
});
helperObj(myReq);
helperObj({
key: "foo",
page: 0,
});
Notes:
- Both
helperInt
andhelperObj
accept both aReq
typed object or a literal object - The
get
function'sparams
type is supposed to match Angular'sHttpParams
Req
interface is used to initialise an object, alter it if needed, before passing it to theget
function
CodePudding user response:
This isn't really an Angular question, it's a Typescript question.
It boils down to:
interface Req {
key: string;
page?: number;
}
// Let's make a type alias for the type `get` expects.
type MyMap = { [key: string]: string | number | boolean | (string | number | boolean)[]; }
const myReq: Req = {key: "foo",page: 0}; // this works
const x: MyMap = { key: "foo", page: 0 }; // this works too
const y: MyMap = myReq; // Type 'Req' is not assignable to type 'MyMap'. Index signature for type 'string' is missing in type 'Req'
So what's the problem?
Well, if Typescript allowed this, you could do:
const x: Req = { key: 'foo', page: 0 };
const y: MyMap = x;
y.key = 0;
y.page = true;
console.log(x.key.toUppercase());
x
has type Req
, so static typing says x.key.toUppercase()
is safe. But we've managed to assign a non-string to x.key
, since x
and y
are references to the same object.
Therefore, Typescript disallows this.
One way to work around it is to spread the object into a new object.
const y: MyMap = { ...myReq };
Typescript can see that the object you're creating is consistent with MyMap
, but since it's a new object subsequent changes won't break the type contract.