-
Notifications
You must be signed in to change notification settings - Fork 12.8k
probable bug in typeof type guard #10442
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
Comments
There are limitations to code analysis for TypeScript, and even in TypeScript 2.0, TypeScript does not narrow indexed based values. To get this to work properly, you would need to put the value into something that can be more easily tracked by TypeScript: const numbers: {[key: string]: number} = {a: 1, b: 2};
const mixed: {[key: string]: number|string} = {a: 1, b: 'two'};
function test(something: {[key: string]: number|string}) {
Object.keys(something).forEach(k => {
const value = something[k];
if (typeof value === 'number') {
Math.floor(value);
} else {
value.toLowerCase();
}
});
}
test(numbers); Prior to TypeScript 2.0, properties of objects weren't narrowed anyways. The TypeScript team though might consider it a suggestion to enhance the code flow analysis in TypeScript to track indexed property values where the static analysis can determine the index value will not change within the scope the narrowing occurs (like in this example). |
An index expression where the indexer expression is |
Would this fall under the same category?
|
@jkjustjoshing this should be working as expected in TS 2.0. The playground is still targeting TS 1.8 |
Hello, I am new to typescript and maybe I got hit by this? I was writing something like this. interface Entry {
[x: string]: string[] | string;
}
interface NormalizedEntry {
[x: string]: string[];
}
interface File {
name: string;
entry: Entry;
}
const getEntry: Function = (file: File): NormalizedEntry => {
const { name, entry } = file;
const normalizedEntry: NormalizedEntry = {};
// Loop over all user defined entries and add to the normalizedEntry
Object.keys(entry).forEach((key: string) => {
normalizedEntry[key] =
Array.isArray(entry[key]) ? entry[key] : [entry[key]];
});
return normalizedEntry;
} But I got error
So I changed to explicit variable as suggested by @kitsonk interface Entry {
[x: string]: string[] | string;
}
interface NormalizedEntry {
[x: string]: string[];
}
interface File {
name: string;
entry: Entry;
}
const getEntry: Function = (file: File): NormalizedEntry => {
const { name, entry } = file;
const normalizedEntry: NormalizedEntry = {};
// Loop over all user defined entries and add to the normalizedEntry
Object.keys(entry).forEach((key: string) => {
const entryPoint: string[] | string = entry[key];
normalizedEntry[key] = Array.isArray(entryPoint)
? entryPoint
: [entryPoint];
});
return normalizedEntry;
} And now it works fine. Does it work under the same category or shall I raise a new issue? |
@swashata type guards can't narrow expressions like Object.keys(entry).forEach((key: string) => {
const en = entry[key];
normalizedEntry[key] = Array.isArray(en) ? en : [en];
}); |
Thanks @RyanCavanaugh for your response 😄. This is exactly what I did (as you can see in the second part of the code). Bdw, do you think documenting this behavior somewhere would help newbies like me? If so, anyplace where I can send a PR? |
This is a known design limitation and not a bug - so I think that at the very least the labels should be changed here (cc @jakebailey ). I also believe that there are already open issues related to this, ones that have more examples/explanations/etc. So it might be worth closing this one in favor of other ones. I can't exactly find those other issues but something tells me that @fatcerberus @MartinJohns and @jcalz might have them on speed dial. |
Ah yes, this one i have found but skipped it exactly because of that reason. |
TypeScript Version: 1.8.0
Code
Link: https://www.typescriptlang.org/play/#src=const%20numbers%3A%20%7B%5Bkey%3A%20string%5D%3A%20number%7D%20%3D%20%7Ba%3A%201%2C%20b%3A%202%7D%3B%0D%0A%0D%0Aconst%20mixed%3A%20%7B%5Bkey%3A%20string%5D%3A%20number%7Cstring%7D%20%3D%20%7Ba%3A%201%2C%20b%3A%20'two'%7D%3B%0D%0A%0D%0Afunction%20test(something%3A%20%7B%5Bkey%3A%20string%5D%3A%20number%7Cstring%7D)%20%7B%0D%0A%20%20Object.keys(something).forEach(k%20%3D%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20if%20(typeof%20something%5Bk%5D%20%3D%3D%3D%20'number')%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20Math.floor(something%5Bk%5D)%3B%0D%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20something%5Bk%5D.toLowerCase()%3B%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%7D)%3B%0D%0A%7D%0D%0A%0D%0Atest(numbers)%3B
Expected behavior:
Type guard would apply to
something[k]
.Actual behavior:
Type guard does not get applied to
something[k]
.The text was updated successfully, but these errors were encountered: