-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Open
Description
π Search Terms
conditionally optional, conditional type generics
π Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about conditional types
β― Playground Link
π» Code
// This is a simplified example of a situation in a React component that
// displays information about a list of data items of type T. It needs to
// be able to determine the human-readable value of each item, so the component
// takes a prop specifying which property of the data item type to extract,
// and if this prop is not provided then the default is to extract the "value"
// property. So I want to enforce that if the generic type T *has* a "value"
// property then the "valueProp" is optional, but if T does *not* have a
// "value" property then the "valueProp" is required.
type Example<T> = {
foo: string;
} & (T extends { readonly value: unknown } ? { valueProp?: keyof T } : { valueProp: keyof T });
// Here is a type that we know has a value property
interface HasValue {
value: string;
}
// Here is another type that does not
type NoValue = {
notValue: string;
}
// If I instantiate Example with the concrete HasValue parameter then valueProp
// is allowed but not required
const ex1a: Example<HasValue> = { foo: "hello" };
const ex1b: Example<HasValue> = { foo: "hello", valueProp: "value" };
// If I instantiate Example with the concrete NoValue parameter then valueProp
// *is* required
const ex2: Example<NoValue> = { foo: "goodbye", valueProp: "notValue" };
// But if I try to instantiate Example with a bounded generic type T then TS claims
// the types are incompatible, even though we know for definite that T must have a
// "value" property.
function makeExample<T extends HasValue>(foo: string): Example<T> {
return { foo }; // TS2322
}π Actual behavior
Type '{ foo: string; }' is not assignable to type 'Example<T>'.
Type '{ foo: string; }' is not assignable to type 'T extends { readonly value: unknown; } ? { valueProp?: keyof T | undefined; } : { valueProp: keyof T; }'.(2322)
π Expected behavior
The generic type variable T is constrained as T extends HasValue, which in turn extends { readonly value: unknown; }, so this should resolve to the { valueProp?: keyof T | undefined; } optional branch in exactly the same way as it does when the expression is typed as the concrete Example<HasValue>.
Additional information about the issue
No response
Metadata
Metadata
Assignees
Labels
No labels