[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Lookup](https://evolu.dev/docs/api-reference/common/Lookup) › Structural

```ts
type Structural<T> = T extends StructuralScalar
  ? T
  : T extends ReadonlyArray<infer Item>
    ? ReadonlyArray<Structural<Item>>
    : T extends StructuralFunction
      ? never
      : T extends object
        ? {
            readonly [
              K in keyof T as K extends symbol
                ? never
                : Extract<T[K], StructuralFunction> extends never
                  ? K
                  : never
            ]: Structural<Exclude<T[K], StructuralFunction>>;
          } & {
            readonly [
              K in keyof T as K extends symbol
                ? K
                : Extract<T[K], StructuralFunction> extends never
                  ? never
                  : K
            ]?: never;
          }
        : never;
```

Defined in: [packages/common/src/Lookup.ts:300](https://github.com/evoluhq/evolu/blob/037c390af081e9944d616ff298a729515c5c5ab7/packages/common/src/Lookup.ts#L300)

Compile-time structural form of `T` for structural lookup APIs.

This exists because [StructuralKey](https://evolu.dev/docs/api-reference/common/Lookup/type-aliases/StructuralKey) is the runtime serialization model,
not a good public generic constraint for interface-shaped objects.
`StructuralKey` models object values with a string index signature, which is
stricter than ordinary interfaces like `{ readonly id: string }` even though
the runtime serializer accepts such plain objects.

`Structural<T>` checks a concrete type recursively at compile time instead:
scalars pass through, arrays recurse, object properties recurse, and
function-valued and symbol-keyed properties are rejected. Symbol-keyed
properties are rejected because runtime serialization reads only enumerable
string keys, so they would be silently ignored. This keeps public structural
APIs ergonomic for interface-based inputs while preserving the same runtime
constraints as structural lookup serialization.

## See

- [StructuralKey](https://evolu.dev/docs/api-reference/common/Lookup/type-aliases/StructuralKey)
- [structuralLookup](https://evolu.dev/docs/api-reference/common/Lookup/functions/structuralLookup)