Skip to main content

createShape

createShape<T>() builds a compile-time checked list of fields to request from the server. It validates dot-paths against T and produces a phantom type that represents the shaped response. Pair it with useData or useTypedData to append _shape=... to requests. Source: src/helpers/shape-helper.ts

Why

  • Keep responses small by requesting only what you need
  • Maintain end-to-end type safety: invalid paths fail at compile time
  • Works with nested objects and arrays (e.g. Records.Items.Name or Posts.Title)

Usage

const shape = createShape<ResponseType>()(['Records.Id', 'Records.Name'])

// shape.fields → ['Records.Id', 'Records.Name']
// shape.type   → { Records: { Id: number; Name: string }[] } (phantom type)
Then pass shape.fields through useData or directly pass the shape object to useTypedData:
const { resource } = useTypedData(httpClient, endpoint, shape)

Arrays and nesting

If Posts is an array, 'Posts.Title' yields { Posts: { Title: string }[] } in shape.type.

Compile-time validation

Invalid paths produce a TypeScript error via ValidatePaths<T, Paths>.
// Error: Invalid path: "profiles.fullName" if fullName doesn’t exist
const shape = createShape<User>()(['id', 'profiles.fullName'])

End-to-end example

import endpoints from '@/api/endpoints'
import { useTypedData } from '@/api/fetchData'
import { createShape } from '@/helpers/shape-helper'

const endpoint = endpoints.teams.list(true)
const shape = createShape<typeof endpoint.type>()(['Records.Id', 'Records.Name'])
const { resource } = useTypedData(httpClient, endpoint, shape)

Best practices

  • Define shapes next to the data hook or at top-level when reused across components
  • Name exported shapes descriptively, e.g. teamListShape
  • Keep shapes minimal; add fields only when needed by the UI

See also