typescript - Definir y usar una lista de pares clave-valor de genéricos
Estoy seguro de que me estoy perdiendo un concepto clave aquí, pero esto es lo que estoy tratando de hacer.
Estas son las definiciones:
export interface ActionError {
message: string;
}
export interface Request<Payload> {
payload: Payload;
}
export interface Response<Payload> {
send: (response?: Payload) => void;
error: (error?: ActionError) => void;
}
export interface Action<RequestPayload, ResponsePayload> {
(request: Request<RequestPayload>, response: Response<ResponsePayload>): void;
}
export interface Actions {
[key: string]: Action<unknown, unknown>;
}
Básicamente, estoy tratando de crear una lista de pares clave-valor de Acciones que pueda funcionar con cualquier tipo que se pueda pasar a una función como la siguiente:
const processActions = (actions: Actions) => {
// Removed for brevity
};
Luego creo un objeto de clave-valor de acciones:
const sampleActions = {
'hello-world': async (
request: Request<{ input: string }>,
response: Response<{ output: number }>
) => {
response.send({ output: 10 });
},
};
Y cuando llamo a processActions con sampleActions:
processActions(sampleActions) Obtengo este error:
Argument of type '{ "hello-world": (request: Request<{ input: string;}>, response: Response<{ output: number;}>) => Promise<void>; }' is not assignable to parameter of type 'Actions'.
Property '"hello-world"' is incompatible with index signature.
Type '(request: Request<{ input: string;}>, response: Response<{ output: number;}>) => Promise<void>' is not assignable to type 'Action<unknown, unknown>'.
Types of parameters 'request' and 'request' are incompatible.
Type 'Request<unknown>' is not assignable to type 'Request<{ input: string; }>'.
Type 'unknown' is not assignable to type '{ input: string; }'
Entonces, ¿qué estoy haciendo mal y cómo puedo hacer que esto funcione con cualquier parámetro de tipo genérico?
Respuesta #1
Entiendo que el error se debe simplemente a la bivarianza de los parámetros de la función. Puedes satisfacer al compilador (y potencialmente inferir un tipo de retorno más específico a partir de la función de procesamiento) utilizando un genérico para el parámetro de acciones, restringido por un tipo que use any para las cargas útiles en lugar de unknown, como se muestra en el ejemplo a continuación.
Ya se use
anyounknown, aún no tendrás información sobre los tipos reales requeridos por las cargas útiles de las acciones dentro de la función de procesamiento. Esta es simplemente la naturaleza del patrón que estás utilizando.
Campo de Juegos TS
export interface ActionError {
message: string;
}
export interface ActionRequest<Payload> {
payload: Payload;
}
export interface ActionResponse<Payload> {
send: (response?: Payload) => void;
error: (error?: ActionError) => void;
}
export interface Action<ReqPayload, ResPayload> {
(request: ActionRequest<ReqPayload>, response: ActionResponse<ResPayload>): void;
}
function processActions <Actions extends Record<string, Action<any, any>>>(actions: Actions) {
// Removed for brevity
}
const sampleActions = {
'hello-world': async (
request: ActionRequest<{ input: string }>,
response: ActionResponse<{ output: number }>,
) => {
response.send({ output: 10 });
},
};
processActions(sampleActions); // ok, hover in playground link to see inferred generics
