-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
String literal that fits keyof X
cannot be used as key of X
in some cases
#32427
Comments
const f = <X extends Config>() => {
/* snip */
};
/**
* Of course you **MUST NOT** set `mapper["POST"]`!
* Because "POST" is not assignable to `X["method"]`
*/
f<{ method : "GET" }>(); Whatever it is you are trying to do, it is a code smell. Change mapper = { POST:1, GET:2 }; to mapper = { GET:2 , POST:1 }; And it will complain about the Change mapper["POST"] = 0; to mapper["GET"] = 0; And it will complain about the |
@AnyhowStep Thank you for pointing out that This is a simplified example, just to illustrate the issue. The actual code that leads me to this is using the type parameter in the parameter list. Now I think the issue is that: let a = { POST:1, GET:2 }; // `a` has type `{ POST: number, GET: number }`
mapper = a; and mapper = { POST:1, GET:2 }; The two pieces of code shall both fail or pass the syntax check. It's weird that one passes the check while the other failed the check. Same thing to: let key : keyof Mapper = "POST";
mapper[key] = 0; v.s. mapper["POST"] = 0; Whats' more, if you do: let key : keyof Mapper = "FETCH"; tsc will complain, so tsc think "FETCH" is not a legit key but "POST" is. |
let a = { POST:1, GET:2 }; // `a` has type `{ POST: number, GET: number }`
mapper = a; // ✔, tsc think this is OK
mapper = { POST:1, GET:2 }; // ❌, but this is not This is because of excess property checking, which only applies to "fresh" object literals. Types are not closed, otherwise you wouldn't be able to have subtypes under structural typing. I still believe the error message for this needs to be reworded because it seems to be very misleading to people as it is right now. See discussion here: #32158 (comment) |
You can rewrite this as type Config = {method:"POST"|"GET"};
type Mapper = {[item in Config["method"]]:number};
function fn<X extends Config>() {
let mapper:Mapper;
let a = {POST: 1, GET: 2}; // `a` has type `{ POST: number, GET: number }`
mapper = a; // ✔, tsc think this is OK
mapper = {POST: 1, GET: 2}; // ✔
let key: keyof Mapper;
key = "FETCH"; // ❌, tsc think "FETCH" is not a valid key
key = "POST"; // ✔
mapper[key] = 0; // ✔, tsc think mapper[key] is OK
mapper["POST"] = 0; // ✔
} to overcome some of these issues. Putting the type declaration inside the function to reference the generic may be problematic here. |
This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow. |
TypeScript Version: 3.5.3
Search Terms:
Code
Expected behavior:
tsc either reports no syntax error on the above code snippet. Or error on all four lines:
Actual behavior:
tsc complains on the two marked above with
Object literal may only specify known properties, and 'POST' does not exist in type 'Mapper'.
But not reporting error on the other 2 lines.Playground Link:
https://www.typescriptlang.org/play/?target=1#code/C4TwDgpgBAwg9gOwGYEsDmUC8UDeUC2EwAFnACYBcUARAAoDyAygCrVQA+NA4gKKtQBfANwAoEQB4AGlAgAPYBARkAzrESo0APgAUASiybcIqCaihIUALIBDMJABOWXFADaUFAvzuEUSS+qEJOTUALpQYVQIAK74AEYQjsJiplAANkQEtg5QVDZ2CaLGpunAUNZOeAwsFACMADRQvMwUAEyCQlAA9J1QAAbWvVDE1qrm0L2VTM1Q0XEJDU2RMfGJvUUm+FkJTtYd3SaAKOQNwMoAxmbEKAgA1hcoqvdQ9ADS65n5jtiT1fWNfK3tEz7KCAGXIGrEoqUSI9Hgg4MBksUMtcICAclAUSA4EgrFt7KIUpinNQAGJ8GAACWoex6YLMZzuNxoZOYlLYsPhZSgADdrKkUGQMai3kTsHQptSuj0oEcoBDSuKWOzVOVefzBZi3psPi5MWFsAAGGmHY4M6FM7UOXWosKPF5avH+KqsfVQI1S0HgyHvK2Kl3uVRwhHCIA
Related Issues:
The text was updated successfully, but these errors were encountered: