David Alonso
David Alonso7mo ago

Validator operation not behaving as expected

I have this table:
const vTableViewResourceAccess = v.object({
...vCommonAccessProps.fields,
resourceType: v.literal("tableView"),
resourceId: v.id("tableViews"),
permissions: v.array(vTableViewPermissions),
});

export const accessTable = defineTable(
v.union(
vWorkspaceAccess,
vFirestoreProjectResourceAccess,
vDataSourceResourceAccess,
...
}
const vTableViewResourceAccess = v.object({
...vCommonAccessProps.fields,
resourceType: v.literal("tableView"),
resourceId: v.id("tableViews"),
permissions: v.array(vTableViewPermissions),
});

export const accessTable = defineTable(
v.union(
vWorkspaceAccess,
vFirestoreProjectResourceAccess,
vDataSourceResourceAccess,
...
}
And I'm trying to create a custom type like so:
export const vResourcePermission = v.union(
...accessTable.validator.members.map((member) => {
return v.object({
resourceType: member.fields.resourceType,
resourceId: v.optional(member.fields.resourceId),
requiredPermissions: member.fields.permissions,
});
})
);
export const vResourcePermission = v.union(
...accessTable.validator.members.map((member) => {
return v.object({
resourceType: member.fields.resourceType,
resourceId: v.optional(member.fields.resourceId),
requiredPermissions: member.fields.permissions,
});
})
);
However when I try to use this validator as an argument of a function, requiredPermissions lets me choose from all permissions and not the scoped ones by the resourceType, and I don't understand why. In case you want to repro: vTableViewPermissions is simply a union of string literals
5 Replies
ian
ian7mo ago
Is this a limitation of the .map types? I wonder if it's losing some of the granularity since each object here is supposed to be treated like it's readonly / const. When this fails, you might have to jump into the types deep end. Or if you don't need to introspect much after, you can just have a single type on vResourcePermission that is something like Validator<Infer<typeof accessTable.validator.members[number]>> to get the types but not the fields
David Alonso
David AlonsoOP7mo ago
not sure I follow, but I can elaborate on my use case: I have a helper function called checkPermissionByResource that takes in this object as an argument (doesn't need to be a validator per se but would be preferred) and I want to be able to enforce that when the resourceType is set to e.g. tableView, that the resource Id can only be of Id<"tableViews"> and the permissions can only be a subset of all permissions, e.g. tableViews:write/read/etc
erquhart
erquhart7mo ago
I think Ian is saying this is maybe due to limitations in how Array.map is typed, so narrowing isn't flowing through the way you'd expect. Don't know if it'll help, but might be worth a try to swap in flatMap, which has more durable typing in my experience. Not sure it's any better with unions, though.
Michal Srb
Michal Srb7mo ago
TypeScript will never use Mapped Type by default without annotations. Mapped Types are what you need to preserve the type of the items in the array: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
Documentation - Mapped Types
Generating types by re-using an existing type.
David Alonso
David AlonsoOP7mo ago
hmm interesting, so you're saying there's a straighforward solution for this case? how do mapped types work with validators? can I just cast the resulting type to a validator with Validator<> or is this not how it works?

Did you find this page helpful?