So I am trying to get safety on my client side GraphQL queries (so if there is a better approach to this let me know).
But what I have been doing is defining my query like this.
export const tenantManagePageQuery = async (tenantId: string) =>
graphQLClient.request<{
tenants: TenantManagePageQueryTenant[];
}>(
/* GraphQL */ `
query tenants($tenantId: String!) {
tenants(tenantIds: [$tenantId]) {
id
description
name
approvedUsers {
id
alias
}
pendingUsers {
id
alias
}
}
}
`,
{ tenantId },
);
in order to define the TenantManagePageQueryTenant
type I do something like this
interface TenantManagePageQueryTenant
extends Pick<Tenant, 'id' | 'description' | 'name'> {}
Where the base Tenant model is my GQL model type.
Is there anyway to do this kind of Pick statement but to also pick the nested properties.
something like
interface TenantManagePageQueryTenant
extends Pick<Tenant, 'id' | 'description' | 'name' | Pick<approvedUser| 'id' | 'alias'> {}
Similar to Colins answer, but coming at it from the opposite direction. If you have an existing interface/type you need to pick apart you can use indexes:
// Existing type
type Tenant = {
id:string;
description:string;
name:string;
approvedUsers: Array<{
id:string;
alias:string;
}>
}
// Pick it apart
type TenantManagePageQueryTenant =
Pick<Tenant, 'id' | 'description' | 'name'> & {
approvedUsers: Array<Pick<Tenant['approvedUsers'][0], 'id' | 'alias'>>
}
As noted in the comments, this can be slightly cleaner:
type TenantSubset = Pick<Tenant, 'id' | 'description' | 'name'>
type ApprovedUserSubset = Pick<Tenant['approvedUsers'][number], 'id' | 'alias'>
type TenantManagePageQueryTenant = TenantSubset & { approvedUsers: Array<ApprovedUserSubset> }
This version, while a little more repetitive, is (subjectively) easier to read:
type TenantManagePageQueryTenant = {
id: Tenant['id'],
description: Tenant['description'],
name: Tenant['name'],
approvedUsers: Array<{
id: Tenant['approvedUsers'][number]['id'],
alias: Tenant['approvedUsers'][number]['alias'],
}>
}