Reputation: 22906
From: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-inference
TypeScript doesn’t assume the assignment of
1
to a field which previously had0
is an error. Another way of saying this is thatobj.counter
must have the typenumber
, not0
, because types are used to determine both reading and writing behavior.The same applies to strings:
const req = { url: "https://example.com", method: "GET" }; handleRequest(req.url, req.method); // Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.
I thought "GET" is a default value assigned to variable 'method' of the object 'req'. What is the error saying?
You can change the inference by adding a type assertion in either location:
// Change 1: const req = { url: "https://example.com", method: "GET" as "GET" }; // Change 2 handleRequest(req.url, req.method as "GET");
Change 1 means “I intend for
req.method
to always have the literal type"GET"
”, preventing the possible assignment of"GUESS"
to that field after. Change 2 means “I know for other reasons thatreq.method
has the value"GET"
“.
What do they mean by adding a type assertion in this case?
What is happening here?
Upvotes: 0
Views: 579
Reputation: 5112
If you hover over req
, you'll see that method
is a string. The types have been "widened". You have to find a way to tell Typescript not to do that. One of these is using const
.
const req = { url: "https://example.com", method: "GET" } as const;
Or you can explicitly say that method
is either "GET" or "POST".
const req: { url: string, method: "GET" | "POST" } = { url: "https://example.com", method: "GET" as "GET" };
or using type assertion like you did as
. (We are often told not to use type assertions but that's a good use case)
This would work as well
const req = { url: "https://example.com", method: "GET" as const }; // const just on method
This little example will help you understand better what's happening:
let num = 3 //number since you can assign something else to num
const num = 3 //3 since it's a const (not supposed to change)
Upvotes: 3
Reputation: 1409
When creating req
, you're basically creating an object with an url: string
and method: string
. Here's an example equal to your code:
interface Request {
url: string;
method: string;
}
const req: Request = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
but this way, you can't ensure that method
is GET or POST, so if handleRequest expects one of those values it will complain if you pass a "string", which could equal to anything.
A solution could be to define a type for the req, for example:
interface Request {
url: string;
method: 'GET' | 'POST';
}
// or using 'type' if you prefer
// type Request = {
// url: string;
// method: 'GET' | 'POST';
// }
const req: Request = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);
Upvotes: 1