You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CFA doesn't work when using generics to associate two function arguments #50205
interfaceRouteParams{'/user': {userId: string},'/product': {productId: string},'/list': {pageSize: number,current: number},}functionnavigateTo<TextendskeyofRouteParams>(url: T,params: RouteParams[T]){// NOT WORK HERE !!!if(url==='/user'){console.log(params.userId)}}// WORKS WELLnavigateTo('/user',{userId: '123'});// @ts-expect-errornavigateTo('/user',{xxxxx: '123'});
🙁 Actual behavior
Property 'userId' does not exist on type '{ userId: string; } | { productId: string; } | { pageSize: number; current: number; }'.
Property 'userId' does not exist on type '{ productId: string; }'.(2339)
CFA works well outside the function call, but not works inside the function.
// 【THIS WORKS !】functiontest(v: 'a'|'b'){if(v==='a'){//@ts-expect-errorif(v==='b'){}}}// 【WHY THIS DOESN'T WORKS ?】functiontest2<Textends'a'|'b'>(v: T){if(v==='a'){//@ts-expect-errorif(v==='b'){}}}
Union types strike again! This recent comment of mine #50145 (comment) comes to mind, specifically the last part:
I’ve found with TS that when generics fail to typecheck in cases where it looks like they should, it’s almost always because you’ve failed to account for the possibility of instantiating them with union types. Having two things typed as T sadly isn’t enough to guarantee they always hold compatible values… and the compiler will let you know about it
Activity
MartinJohns commentedon Aug 6, 2022
The error is correct. You wrongly assume that
Twill always only be one specific key, but this is valid code:You want #27808.
k8w commentedon Aug 6, 2022
Martin Johns (@MartinJohns)
Actually,
There is not'/user' | '/product', because it is infered as'/user':MartinJohns commentedon Aug 6, 2022
It's allowed to explicitly specify the type parameter, as I did. In that case the type parameter is not inferred anymore.
But even if you let it infer the type you can have the same issue:
Within the implementation of the function the compiler can't know if the type represents only one key, or multiple. So it errs on the safe side.
k8w commentedon Aug 6, 2022
Tmaybe multiple keys indeed, but when it checked byurl === '/user', shouldn't CFA narrowed the T to single key?For example, this works well:
So why it doesn't works inside the function ?
MartinJohns commentedon Aug 6, 2022
No. You're only narrowing the type of the specific variable.
Tcan be"/user" | "/product", andurlis"/user", butparamsisRouteParams["/product"]. This is perfectly legit to call, as I demonstrated twice.k8w commentedon Aug 6, 2022
Actually
urlis not narrowed at all, see this:whzx5byb commentedon Aug 6, 2022
Zhongyang Wang (@k8w) I'm not sure why
vis still marked asT extends 'a' | 'b'but it is narrowed in fact. See the examples in #43183.fatcerberus commentedon Aug 6, 2022
Union types strike again! This recent comment of mine #50145 (comment) comes to mind, specifically the last part:
typescript-bot commentedon Aug 10, 2022
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.