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
helperIntandhelperObjaccept both aReqtyped object or a literal object - The
getfunction'sparamstype is supposed to match Angular'sHttpParams Reqinterface is used to initialise an object, alter it if needed, before passing it to thegetfunction
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.
