Generic derived value type
See original GitHub issueHey 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: priceFilterValue
Actual behavior: Code
const value: filterValueType<T>
Playground Link: Playground
Related Issues:
Issue Analytics
- State:
- Created 5 years ago
- Reactions:6
- Comments:10 (5 by maintainers)
Top Results From Across the Web
Constraints on type parameters - C# Programming Guide
Use type parameters as constraints on generic classes in scenarios in which you want to enforce an inheritance relationship between two type ...
Read more >Generics, Inheritance, and Subtypes (The Java™ Tutorials ...
You can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or...
Read more >Assigning a generic type for derived classes from an abstract ...
From there, I am lost. TypeScript Playground link abstract class Base<T> { abstract value: T; } class Derived ...
Read more >Generic Types and Inheritance - Mastering C# and .NET
Generic Types and Inheritance ; Same-type inheritance · BetterHolder.cs · 3. // The same type parameter as the base class ; Non-generic child...
Read more >C#. Hierarchies of generic classes - BestProg
Generic classes support an inheritance mechanism and can form hierarchies. Any generic class that takes a type T as a parameter can be ......
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@andyrichardson The behavior is still as expected:
This isn’t the case. Given that
state === 'c'
, you only know that'c'
is a subtype ofS
. In particular, (e.g.)S = 'a' | 'c'
is still entirely possible:This value can be passed to
myFun
above; you’ll find thatstate === 'c'
as expected, and also thatadditionalProp
has typestring[]
, notnull
. This works since conditional types are distributive, meaning thatX | Y extends T ? A : B
is really the same as(X extends T ? A : B) | (Y extends T ? A : B)
. This means that in the above,additionalProp
really does have the typestring[] | null
, since'a'
follows the left path and'c'
follows the right one.You can avoid distribution with the following trick:
by wrapping the two types in a single-element tuple. However, this won’t actually solve the problem, because it is still impossible to distinguish (solely using flow types) that
S
is actually'c'
and not'a' | 'c'
or'a' | 'b' | 'c'
or'b' | 'c'
(since you can only learn what it is allowed to be, and not what it is not allowed to be, from runtime checks).The following trick almost works, except the TS’s flow-typing is not sophisticated enough to understand that deducing
S = 'c'
is actually correct:This makes the code actually sound (since the
exampleValue
above will no longer compile) since it enforces that the tag is consistently a singleton throughout the type, although you’ll need to perform a cast inside the function to convince tsc that it really behaves as intended.The error absolutely is produced (provided that
--strictNullChecks
is 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.