TypeScript Version: 3.8.0-dev.20200128
Search Terms:
Code
interface Section<T extends number | string> {
items: T extends number ? number[] : string[];
}
export function test<T extends number | string>(arg: Section<T>): void {
arg.items.forEach((): void => console.log());
arg.items.map((): void => console.log());
}
Expected behavior:
Typescript to either can determine the signature of both the map callback AND forEach callback or to understand none.
Actual behavior:
It doesn't have any problem with forEach but raises this error for the map clause:
This expression is not callable.
Each member of the union type '(<U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[]) | (<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.
Playground Link:
http://www.typescriptlang.org/play/?ts=3.8.0-dev.20200128&ssl=9&ssc=1&pln=1&pc=1#code/JYOwLgpgTgZghgYwgAgMoQWYB7EAeAFWQgA9IQATAZ2RAFcBbAI2mQB9kqwpQBzAPmQBvAFDJkwSAyoAuZEVLlqtRiyjIA-CubQA2gF1kcrjxC8DAbhEBfESNIAHbFDDIYdEJhwhkkLoWIyCEoaeh11DhM+fgAKOCheOXQvXEJ+AEo5ADdsYAphMWR43gA6SQhpEphnAFFEAAsYmMzkHLzkAF5BBFwqbAAbCBL+7F5m9KtxYrKpKhKGOAcmlrb8ruQekD7B4dHxq1sgA
Related Issues:
https://github.com/microsoft/TypeScript/issues/33591
Changing the type of the items field to
items: (T extends number ? number : string)[];
makes it compile without any errors.
Looks like another duplicate of #7294, mentioned in documentation as caveats for improved behavior for calling union types:
This new behavior only kicks in when at most one type in the union has multiple overloads, and at most one type in the union has a generic signature. That means methods on
number[] | string[]likemap(which is generic) still won’t be callable.On the other hand, methods like
forEachwill now be callable, but undernoImplicitAnythere may be some issues.
I'm not sure if it's the same thing, I just edited my issue I think it was misleading, the issue I'm reporting is that typescript should have same behavior for forEach and map, it's raising an error for map but none for forEach.
Please read the TS3.3 release notes for Improved behavior for calling union types, including the full Caveats section, and let me know if there's something in your issue that isn't covered by that.
It's explicitly said in the caveats that map doesn't work and forEach works, apparently because map is a generic because of its return type. So I guess the developers are already aware of this issue and we can close this.
I just noticed that issue is closed without resolving the issue described here, so I guess it should stay open.
map is generic (because it has an output type) and forEach isn't.
@RyanCavanaugh map being a generic doesn't imply that it should raise this error, I understand that it matters internally, but it's still an issue with typescript and I guess you want it to be resolved and in that case I guess we should keep related issues open, closing all issues related to this problem doesn't help with solving it, instead we can consider changing the title unless you know another open issue is tracking this problem.
@sassanh Please don't tell us our what our own metadata means. For us, "Open" means that we have the ability to schedule engineering work to address the problem; "Closed" means that it doesn't. This issue being closed doesn't mean that we're unaware of the limitation.
I wasn't telling you what your metadata mean, I'm sorry if it was interpreted that way, I among many others usually use issue trackers to reflect "awareness" about problems on it and we usually close an issue only when it's resolved, seems like it's different here, is there any document explaining how issues are tracked in TypeScript repository that I can read so that I can avoid such misunderstandings and stay productive in my future bug reports?
Fair enough; I owe you a FAQ update on that one
@sassanh Please don't tell us our what our own metadata means. For us, "Open" means that we have the ability to schedule engineering work to address the problem; "Closed" means that it doesn't. This issue being closed doesn't mean that we're unaware of the limitation.
Ho @sassanh I dream of a world where one doesn't fear to comment on
the rest of the comment is interesting and important to me because I didn't know that _«For [you], "Open" means that [you] have the ability to schedule engineering work to address the problem; "Closed" means that it doesn't. This issue being closed doesn't mean that [you're] unaware of the limitation.»_
My code:
public listMap<R>(
fn: (
value: T | Promise<T>,
index: number,
array: T[] | Promise<T>[]
) => R | Promise<R>,
thisArg?: any
) {
if (this.value !== null) {
return new MaybeList<R>(this.value.map<R>(fn, thisArg))
}
return new MaybeList<null>();
}
this.value is defined by private value!: T[] | Promise<T>[] | null;
error message: (this.value.map())
This expression is not callable. Each member of the union type
'(<U>(callbackfn: (value: T, index: number, array: T[]) =>
U, thisArg?: any) => U[]) |
(<U>(callbackfn: (value: Promise<T>, index: number, array: Promise<T>[]) =>
U, thisArg?: any) => U[])'
has signatures, but none of those signatures are compatible with each other.
ts(2349)
Most helpful comment
Fair enough; I owe you a FAQ update on that one