Repository navigation
Generic derived value type #28597
Copy link
Copy link
Open
Labels
Domain: Conditional TypesThe issue relates to conditional typesThe issue relates to conditional typesExperience EnhancementNoncontroversial enhancementsNoncontroversial enhancementsSuggestionAn idea for TypeScriptAn idea for TypeScript
Milestone
Description
Hey guys.
I can not see if I'm doing anything wrong here. I am expecting to be able to get exact type from generic type ...
Is this just limitation of typescript or i am doing anything whrong here?
TypeScript Version: 3.1.3
Search Terms:
Generic derived value type
Code
export type filterTypeName = 'price' | 'price_range';
export type priceFilterValue = {
from: number;
to: number;
};
export type priceRangeFilterValue = {
fromRange: number;
toRange: number;
};
export type filterValueType<T extends filterTypeName> =
T extends 'price' ? priceFilterValue
: T extends 'price_range' ? priceRangeFilterValue : never;
type productFilterParameters<T extends filterTypeName> = {
filter: T;
value: filterValueType<T>;
};
function addProductFilter<T extends filterTypeName>(params: productFilterParameters<T>) {
switch (params.filter) {
case 'price':
const priceFrom = params.value.from; //Property 'from' does not exist on type 'filterValueType<T>'
break;
default:
break;
}
}
// parameter value is derivered based on filter type... not working id function definition
addProductFilter({ filter: 'price', value: { from: 1, to: 2 } });
//expected behavior something like this
type productFilterParametersCorrect = {
filter: 'price';
value: priceFilterValue;
} | {
filter: 'price_range';
value: priceRangeFilterValue;
}
function addProductFilterCorrect(params: productFilterParametersCorrect) {
switch (params.filter) {
case 'price':
const priceFrom = params.value.from; // correct
break;
case 'price_range':
const priceRangeFrom = params.value.fromRange; // correct
default:
break;
}
}Expected behavior:
Code
const value: priceFilterValueActual behavior:
Code
const value: filterValueType<T>Playground Link:
Playground
Related Issues:
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Domain: Conditional TypesThe issue relates to conditional typesThe issue relates to conditional typesExperience EnhancementNoncontroversial enhancementsNoncontroversial enhancementsSuggestionAn idea for TypeScriptAn idea for TypeScript
Activity
weswigham commentedon Nov 19, 2018
Anders Hejlsberg (@ahejlsberg) it seems like we might be able to recognize discriminants in conditional types similarly to unions - though it also seems much less straightforward to resolve them.
Nathan-Fenner commentedon Nov 20, 2018
This isn't a bug (see this discussion in #24085 ).
Consider the following code:
The last is because (for whatever reason), conditional types are automatically mapped over unions.
Therefore, I can make the following call to the function:
with no errors. Everything type checks, as it's supposed to. Inside the function, the case will match "price", and yet there will be a
fromRangeandtoRangefield but nofromand noto.I have a proposal at #27808 to add an
T extends_oneof("price", "price_range")constraint which would make the above code work as expected.jurajkocan commentedon Nov 22, 2018
Wesley Wigham (@weswigham) so is this possible to implement in to the typescript or should i find another solution?
if so i will just wait for it.
andyrichardson commentedon May 2, 2019
I've just come across this issue myself. Here's a quick reproduction.
It looks as though, despite the conditional statement, the type of
arg.stateremains to be undetermined.Nathan-Fenner commentedon May 3, 2019
Andy Richardson (@andyrichardson) that behavior is as expected (although for a completely different reason).
All operations are legal on
neversince it's a bottom type. It's impossible to have a value of typenever(at least without cheating), so if you do get one, the impossible has already happened, and therefore there's nothing wrong with letting you do "impossible" operations.Since
.lengthis valid on bothneverandstring[]there's no problem.TypeScript does provide a best-effort check for operations on definitely
nevertypes, since those are likely mistakes. But for a value that's only maybeneverit would be counterproductive to error.Replacing
neverwithnullwill give you an error, as expected.andyrichardson commentedon May 3, 2019
Nathan Fenner (@Nathan-Fenner) this isn't an issue relating to the use of
null. If you replace, from the example,neverwithnullyou will see that an error is still not produced.The problem is that following the condition
if (arg.state === 'c') {the type of arg within the conditional body should beMyInterface<'c'>(and therefore additional prop is of typenever). This isn't the case as the type remains to be unknown and therefore the type ofarg.additionalPropremains to be undetermined (string[] | neverorstring[] | nullas with your suggestion).Nathan-Fenner commentedon May 3, 2019
The error absolutely is produced (provided that
--strictNullChecksis on:See playground for example
You obtain the error:
As expected. Your issue is due to misuse of
never, not a bug in conditional types. Even then, it would be unrelated to the original issue here.6 remaining items
agalazis commentedon Jul 21, 2019
Hello I was facing the same issue in my action factory (I might come back later with a minimal example). I think we need to come up with a way to declare the type as a Singletton or accept that it is singleton if it extends a singleton. In my case, it would be even more useful to allow a generic of singleton types eg ActionType<'my feature', 'my action type','my action name'>( being the type of 'myfeature | my action | my action name'
(I was trying to achieve something like #12754 (comment) with the issue being that the resulting type couldn't be used as a discriminant)