Typescript seleccionar de argumento de función
En TypeScript, ¿hay una manera de que useContext dentro de lo siguiente seleccione y devuelva el tipo de valor del Provider?
function Provider<Props = {value: number}>(props: Props) { }
function useContext<Value>(context: Context<Value>): Pick<Value, 'value'> { return 0 }
De manera que "Consumidor" devolverá el tipo: número cuando se use de la siguiente manera
function Consumer<Props>(props: Props) { return useContext(Provider) }
...Para contexto adicional:
interface Component<Props = {}> { (props: Properties<Props>): Node }
interface Context<Value> extends Component<{value: Value}> {}
O alternativamente, dado
function Provider({value, children}: {value: string, children: any}) {
return h(Context, {value: 'value'}, children)
}
const value = useContext(Provider)
¿Cómo se atribuiría la constante "value" al "value" que se encuentra en el objeto {value: 'value'} suponiendo que la función "h" devuelve una interfaz:
interface {type: Context, props: {value: 'value}, children: children}
He intentado usar Pick, props> donde Type es "Provider" y luego usar Pick del resultado de ese Pick, props>, 'value'>.
Sin embargo, eso no parecía funcionar.
Respuesta #1
Hay una forma ingeniosa de extraer tipos de propiedades llamada 'tipos de búsqueda' (Notas de TypeScript 2.1). La sintaxis es:
MyType['value'] // number
Donde MyType contiene una propiedad value: number.
Editar: Estoy teniendo problemas para seguir tu ejemplo, intenté expandir el parámetro 'context' de useContext y terminé con esto:
function useContext<Value>(context: Context<Value>): Pick<Value, 'value'>;
=> function useContext<Value>(context: Component<{value: Value}>): Pick<Value, 'value'>
=> function useContext<Value>(context: (props: Properties<{value: Value}>) => Node): Pick<Value, 'value'>
Si seguimos el tipo Value hasta la tercera expansión, vemos que no hay ninguna restricción; nada que le diga al compilador que el tipo Value debe tener una propiedad 'value'. La única manera de que el compilador de Typescript devuelva un tipo de useContext(...) basado en Value["value"] es si hay alguna restricción que le indique al compilador que 'value' existe en el tipo.
Una opción, si agregas una restricción de tipo <Props extends {value: number}={value: number}> a Component y Provider, el compilador podrá inferir que props tiene una propiedad 'value'.
Otra opción, indicar explícitamente al compilador qué propiedad ya sabes que existe usando keyof y pasando la cadena literal de la clave (se añadió el parámetro 'key' y se cambió el tipo de retorno a Pick<Value, K>):
function useContext<Value, K extends keyof Value>(context: Context<Value>, key: K): Pick<Value, K> {
// ...
}
var value = useContext(Provider, 'value');
