Ir para o conteúdo principal

Geração de tipos

Geração de tipos

O AppKit pode gerar automaticamente tipos TypeScript para suas queries SQL, garantindo segurança de tipos de ponta a ponta, do banco de dados até a UI.

Objetivo

Gerar declarações TypeScript com segurança de tipos para chaves de query, parâmetros e linhas de resultado.

Todos os arquivos gerados ficam em shared/appkit-types/, um para cada finalidade: analytics.d.ts (tipos de query SQL), serving.d.ts (tipos de serving endpoint de modelos) e metric-views.d.ts (tipos de metric view). Um único comando (e o plugin do Vite) gera todos eles de uma só vez; consulte Tipos de metric view. Os arquivos usam declare module para estender interfaces existentes, de modo que os tipos passam a valer globalmente — você nunca precisa importá-los. O TypeScript os descobre automaticamente por meio de "include": ["shared/appkit-types"] no seu tsconfig.

Plugin do Vite: appKitTypesPlugin

A abordagem recomendada é usar o plugin do Vite, que monitora seus arquivos SQL e regenera os tipos automaticamente durante o desenvolvimento.

Configuração

  • outFile?: string - Caminho do arquivo de saída (padrão: shared/appkit-types/analytics.d.ts)
  • watchFolders?: string[] - Pastas a monitorar em busca de arquivos SQL (padrão: ["../config/queries"])

Exemplo

// client/vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { appKitTypesPlugin } from "@databricks/appkit";

export default defineConfig({
  plugins: [
    react(),
    appKitTypesPlugin({
      watchFolders: ["../config/queries"],
    }),
  ],
});

Detalhe importante

Quando o frontend é servido pelo AppKit em modo de desenvolvimento, o servidor de desenvolvimento do AppKit já inclui o appKitTypesPlugin() internamente. Mesmo assim, é recomendável mantê-lo no pipeline de build do cliente caso você execute vite build separadamente.

CLI: npx @databricks/appkit generate-types

Para gerar tipos manualmente ou em pipelines de CI/CD, use o comando da CLI:

# Requer DATABRICKS_WAREHOUSE_ID (ou passe como 3º argumento)
npx @databricks/appkit generate-types [rootDir] [outFile] [warehouseId]

Exemplos

  • Gerar tipos usando o ID do warehouse definido no ambiente

    npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts
  • Gerar tipos informando o ID do warehouse explicitamente

    npx @databricks/appkit generate-types . shared/appkit-types/analytics.d.ts abc123...
  • Forçar a regeneração (ignorar o cache)

    npx @databricks/appkit generate-types --no-cache

Prontidão do warehouse e a flag --wait

Por padrão, o generate-types é não bloqueante: ele nunca espera pelo seu SQL warehouse — nem falha por causa dele. Ele grava imediatamente os melhores tipos que consegue (reaproveitando tipos em cache quando a query não mudou; caso contrário, result: unknown) e então inicia um worker em segundo plano desacoplado que atualiza os tipos reais assim que o warehouse fica pronto. Isso mantém npm install (postinstall) e npm run dev (predev) rápidos e resilientes a um warehouse frio ou momentaneamente inacessível. O plugin de dev do Vite se comporta da mesma forma: os tipos aparecem instantaneamente e são atualizados no próprio lugar assim que o warehouse fica ativo.

Use --wait em builds de CI e de produção, nos quais os tipos corretos precisam estar disponíveis antes que o build prossiga:

npx @databricks/appkit generate-types --wait

Resiliência em CI: tipos versionados como fallback

No modo bloqueante (--wait), o gerador tenta obter os tipos reais do seu warehouse, mas recorre aos arquivos de tipos versionados (shared/appkit-types/analytics.d.ts e, quando houver Metric Views configuradas, shared/appkit-types/metric-views.d.ts) como fallback quando o warehouse está inacessível. Esses arquivos gerados devem fazer parte do seu repositório. Em um checkout novo de CI, todo build tenta executar o DESCRIBE no warehouse; os tipos versionados só entram em cena quando isso não é possível.

O gerador nunca sobrescreve tipos versionados com tipos degradados (result: unknown) — ou ele grava tipos reais, ou não grava nada.

Uma taxonomia de falhas em dois grupos determina se o build quebra ou recorre aos tipos versionados:

  • Falhas determinísticas (sempre quebram o build): erros de sintaxe SQL nas suas queries (falha genuína do DESCRIBE em um warehouse acessível), HTTP 404 (ID de warehouse inválido ou desconhecido), HTTP 400 (requisição malformada). São erros de desenvolvimento ou de configuração que os tipos versionados não devem mascarar.
  • Falhas ambientais (condicionadas aos tipos versionados): falhas de autenticação (401/403), rede inacessível, warehouse indisponível (frio, em exclusão ou já excluído), tempo limite de espera pelo estado RUNNING, ou qualquer falha não reconhecida. Se todos os arquivos de tipos exigidos pelo app existirem, o build os mantém, emite um aviso destacado no stderr e é concluído com sucesso (exit 0). Se faltar algum arquivo obrigatório, o build quebra com uma mensagem instruindo você a executar npx @databricks/appkit generate-types --wait localmente (em um warehouse acessível) e a versionar os arquivos de tipos gerados.

O aviso destacado é uma única linha no stderr, fácil de localizar com grep, que indica a causa geral (autenticação bloqueada / warehouse inacessível / warehouse indisponível) e o ID do warehouse, de modo que os logs de CI deixem claro que o build recorreu aos tipos versionados.

Em um app com Metric Views, o metric-views.d.ts já precisa existir para que uma falha ambiental consiga recorrer ao fallback — o analytics.d.ts sozinho não satisfaz essa condição.

O template do app já deixa isso configurado para você: postinstall e predev executam o modo padrão não bloqueante, enquanto prebuild executa com --wait.

Tipos de metric view

O generate-types (e o plugin do Vite) emitem tipos de metric view de forma aditiva — não há um comando separado. Quando existe um arquivo config/metric-views/definitions.json, a mesma execução que gera os tipos das suas queries também executa DESCRIBE em cada UC Metric View declarada e grava dois artefatos:

  • shared/appkit-types/metric-views.d.ts — estende a interface MetricRegistry para que useMetricView('<key>', …) tenha autocompletar e verificação de tipos. As medidas, dimensões e seus metadados semânticos (tipo SQL, nome de exibição, formato, granularidades de tempo) de cada view são codificados no nível de tipo. As chaves de linha selecionadas usam o tipo de valor de transmissão JSON_ARRAY real (string | null); o tipo SQL continua disponível nos metadados para parsing/formatação deliberados.
  • config/metric-views/metadata.generated.json — a metade de runtime da mesma passagem, que carrega esses metadados por coluna como valor, ao lado do seu definitions.json escrito manualmente. A rota de métricas o descobre automaticamente e anexa os metadados das colunas solicitadas ao payload da resposta, dispensando qualquer ligação de plugin. Faça commit dele junto com seus tipos gerados; como é gerado, não o edite manualmente.

Se config/metric-views/definitions.json estiver ausente, o caminho de métricas permanece inativo (nada é emitido). Quando presente, ele segue o mesmo contrato de prontidão do warehouse que os tipos de query: na execução não bloqueante padrão, uma view que ainda não pode ser descrita — um warehouse frio ou uma fonte inválida/inacessível — é gravada com tipos permissivos e um aviso; já sob --wait, as metric views obedecem à taxonomia de dois grupos (falhas ambientais recuam para o metric-views.d.ts versionado + aviso; falhas determinísticas, como definições malformadas, quebram o build). Um definitions.json malformado (JSON inválido ou uma fonte que não seja um FQN de três partes do UC) falha imediatamente em todos os modos.

O definitions.json é indexado pela chave da métrica; cada entrada indica o FQN de três partes do UC da view e, opcionalmente, o executor sob o qual ela roda (app_service_principal, o padrão, ou user):

{
  "$schema": "https://databricks.github.io/appkit/schemas/metric-source.schema.json",
  "metricViews": {
    "revenue": { "source": "catalog.schema.revenue_metrics" },
    "customers": {
      "source": "catalog.schema.customer_metrics",
      "executor": "user"
    }
  }
}

A linha opcional $schema habilita o autocompletar no editor e a validação com base no schema publicado.

Como funciona

O gerador de tipos:

  1. Varre a pasta config/queries/ em busca de arquivos .sql
  2. Analisa as anotações de parâmetros SQL (por exemplo, -- @param startDate DATE)
  3. Conecta-se ao seu Databricks SQL Warehouse para inferir os tipos das colunas de resultado
  4. Gera interfaces TypeScript para os parâmetros e os resultados das queries
  5. Cria um tipo QueryRegistry para executar queries com segurança de tipos

Parâmetros durante o DESCRIBE QUERY

A geração de tipos descreve cada query sem vincular parâmetros reais e, por isso, substitui cada :param por um valor padrão de marcação (por exemplo, '' para strings). Isso quebra queries cuja estrutura depende de um valor — em especial nomes de tabela dinâmicos via IDENTIFIER(:catalog || '.schema.table'). Anote esses parâmetros com um valor de exemplo (-- @param catalog STRING = main) para que a chamada describe consiga resolver uma tabela real. O valor de exemplo é usado apenas no momento da geração de tipos; em runtime, a query continua vinculando o parâmetro real. Consulte Parâmetros SQL → Valores de exemplo.

Usando os tipos gerados

Depois de gerar os tipos, seu IDE oferecerá autocompletar e verificação de tipos:

import { useAnalyticsQuery } from "@databricks/appkit-ui/react";
import { sql } from "@databricks/appkit-ui/js";

// O TypeScript sabe que "users_list" é uma chave de query válida
// e quais parâmetros ela espera
const { data } = useAnalyticsQuery("users_list", {
  status: sql.string("active"),
  limit: sql.number(50),
});

// O TypeScript conhece o formato das linhas do resultado
data?.forEach((row) => {
  console.log(row.email); // ✓ o autocomplete funciona
});

Veja também

Databricks Developer Hub

Pronto para lançar seu próximo aplicativo baseado em agentes em minutos?

Ler a documentação