Seeking insight on the typing issue causing a compiler error in the code snippet below. Any suggestions for maintaining type-safety without resorting to any
or as
? Avoiding these workarounds is important to me.
The challenge lies in the evidence()
call, crucial to emulating type-constrained calls required in actual scenarios.
I believe I've correctly constrained the type, but upon relying on the constraint, I'm warned about potential subtype discrepancies that don't align with my understanding of the "artist" value restriction.
The intended purpose of extends "artist"
is to enforce this restriction. Opting not to use TaleState<"artist">
allows for inclusion of other roles alongside "artist", while ensuring "artist" is present for the logic within the evidence()
call to function properly.
The specific error can be seen inline in the following code excerpt and further detailed under PROBLEM. The error is also visible in the Typescript Playground.
export type Role = "artist" | "writer" | "maker";
export interface TaleState<TaleRole extends Role> {
rolesVisited: Record<TaleRole, boolean>;
}
export function evidence<TaleRole extends Role, Evidenced extends TaleRole>(
state: TaleState<TaleRole>,
...roles: [Evidenced, ...Evidenced[]]
) {
for (const role of roles) {
state.rolesVisited[role] = true;
}
}
function artistTale<TaleRole extends "artist" >(
state: TaleState<TaleRole>
) {
/** the call below has a compiler error which reads...
* Argument of type '"artist"' is not assignable to parameter of type 'Evidenced'.
* '"artist"' is assignable to the constraint of type 'Evidenced',
* but 'Evidenced' could be instantiated with a different subtype of constraint '"artist"'
*/
evidence(state, "artist");
}
PROBLEM
A typing issue surfaces within the artistTale function. My expectation was to run this function on any TaleState that includes "artist" in its Roles.
The line featuring evidence(state, "artist");
triggers the compilation error...
Argument of type '"artist"' is not assignable to parameter of type 'Evidenced'. '"artist"' is assignable to the constraint of type 'Evidenced', but 'Evidenced' could be instantiated with a different subtype of constraint '"artist"'
I struggle to comprehend why extends "artist"
isn't a fitting constraint here.
There seems to be a fundamental misunderstanding on my part, likely related to how extends
dictates literal typings, leading to these predicaments.
Various attempts were made to control inference so types align with state
values, facing new challenges along the way.
QUESTION
Can someone shed light on why this results in a type error?
How should artistTale be defined instead, allowing manipulation on adequately constrained TaleStates for valid evidence callbacks within the supported roles?
BACKGROUND
This flawed example stems from a portfolio API project focusing on portraying Tales through Roles.
Tale typing enforces declared roles requiring validation through evidence callbacks affecting state updates. Autocompletion aids in role references, enabling tracking of evidenced roles during Tale execution testing. Hence, heavy reliance on inference in the API design.
This line showcases an instance from the ongoing experimental API development. Aiming for concise, declarative nested function calls while preserving type-safety. Each Tale specifies the roles it evidences, preventing unauthorized role evidence calls nested inside tale()
, underscoring the importance of Evidenced
inference.
Unfortunately, accommodating the one-off illuminationsIntro
from this line necessitated declaring it as Beat<any>
. This broadening of type scope relinquishes constraints tied solely to tale-valid roles, potentially inviting errors at both type and runtime levels into the system.