I have a situation where I have an array of generic items (Item
), and within the item itself, I want the generic parameter to be inferred and specific.
That is, I want have an array of generic items, but each one can have a different generic typing, and that should be retained.
type Item<T> = {
value: T;
fn: (value: T) => void;
}
function usesItem<T>(item: Item<T>) {
}
// This is fine - the value is inferred
usesItem({
value: 999,
fn: (value) => {
//value is inferred as number
}
})
First approach, declare an Array<Item<unknown>
:
function usesItems1(items: Array<Item<unknown>>) {
}
usesItems1([{
value: 999,
fn: (value) => {
// value is unknown - we want it to be number
}
}
])
Second approach: introduce the generic from the function:
function usesItems2<T>(items: Array<Item<T>>) {
}
// appears to work...
usesItems2([{
value: 999,
fn: (value) => {
// value is number
}
}
])
// ...but it doesn't really
usesItems2([{
value: 999,
fn: (value) => {
// value is number
}
}, {
// Type 'string' is not assignable to type 'number'.(2322)
value: "aaa",
fn: (value) => {
}
}
]);
Third approach - use the infer
keyword, I tried a couple of approaches:
type InferredItem1<T> = T extends Item<infer R> ? Item<R> : never;
function usesItems3(items: Array<InferredItem1<unknown>>) {
}
usesItems3([{
//Type 'number' is not assignable to type 'never'.(2322)
value: 999,
fn: (value) => {
}
}
]);
type InferredItem2<T extends Item<unknown>> = T extends Item<infer R> ? Item<R> : never;
function usesItems3b(items: Array<InferredItem2<Item<unknown>>>) {
}
usesItems3b([{
value: 999,
fn: (value) => {
// value is unknown
}
}
]);
How can I achieve what I want?
Or, if this isn't possible I guess a canonical reference to the Github issue/similar that gets into it.