ts-proto
transforma seus arquivos.proto
em arquivos digitadores idiomáticos fortemente tipados!
A liberação 2.x do TS-Proto migrou a protobuf de baixo nível serializando que seu método encode
e decode
use o pacote venerável, mas envelhecido e estagnado, protobufjs
para @bufbuild/protobuf
.
Se você usou apenas os métodos encode
e decode
, isso deve ser amplamente uma alteração sem quebra.
No entanto, se você usou algum código que usou as classes ou aulas Writer
ou Reader
protobufjs
, precisará atualizar seu código para usar as novas classes @bufbuild/protobuf
:
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
Se migrar para @bufbuild/protobuf
for um bloqueador para você, você poderá fixar sua versão ts-proto
para 1.x
Isenção de responsabilidade e desculpas: eu pretendia lançar o TS-proto 2.x como uma liberação alfa, mas não obtive a configuração de liberação semântica correta e, portanto, o TS-Proto 2.x foi publicado como um grande lançamento sem um alfa adequado /Ciclo beta.
Se você pudesse arquivar relatórios (ou melhores PRs!) Para quaisquer problemas que você encontrar enquanto o lançamento ainda estiver fresco, isso seria muito apreciado.
Quaisquer dicas ou truques para outras pessoas na migração também seriam apreciadas!
TS-proto
Índice
Visão geral
Investir rápido
BUF
Esm
Metas
Não-objetivos
Tipos de exemplo
Destaques
Prevenção de lotes automáticos / n+1
Uso
Opções suportadas
Suporte de Nestjs
Modo de assistência
Implementação básica de GRPC
Patrocinadores
Desenvolvimento
Suposições
Pendência
Um de manuseio
Valores padrão e campos não atendidos
Tipos conhecidos
Tipos de invólucro
Tipos JSON (tipos de estrutura)
Timestamp
Tipos de números
Status atual dos valores opcionais
O TS-proto gera tipos de texto de texto dos esquemas Protobuf.
Ou seja, dado a uma person.proto
esquema como:
pessoa da mensagem {nome da string = 1; }
O TS-proto gerará um arquivo de person.ts
como:
Pessoa da interface { Nome: string} const Person = { Encode (pessoa): Writer {...} Decode (leitor): Pessoa {...} Tojson (pessoa): desconhecido {...} Fromjson (Data): Pessoa {...}}
Ele também conhece serviços e também gerará tipos para eles, ou seja,:
Interface de exportação PingService { Ping (Solicitação: PingRequest): Promise <PingResponse>;}
Também gerará implementações de clientes do PingService
; Atualmente, Twirp, GRPC-Web, GRPC-JS e NESTJs são suportados.
npm install ts-proto
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. ./simple.proto
(Observe que o nome do parâmetro de saída, ts_proto_out
, é nomeado com base no sufixo do nome do plug-in, ou seja, "ts_proto" sufixo no --plugin=./node_modules/.bin/protoc-gen-ts_proto
parâmetro se torna o prefixo _out
,,, As convenções da CLI de Per Pro protoc
.)
No Windows, use protoc --plugin=protoc-gen-ts_proto=".node_modules.binprotoc-gen-ts_proto.cmd" --ts_proto_out=. ./simple.proto
(ver #93)
_opt
protoc
3.0.0
estar usando um protoc
Isso gerará arquivos de origem *.ts
para os tipos de *.proto
fornecidos.
Se você deseja empacotar esses arquivos de origem em um pacote NPM para distribuir aos clientes, basta executar tsc
neles como de costume para gerar os arquivos .js
/ .d.ts
e implantar a saída como um pacote NPM regular.
Se você estiver usando BUF, passe strategy: all
no seu arquivo buf.gen.yaml
(docs).
Versão: v1plugins: -Nome: tsout: ../gen/tsstrategy: AllPath: ../node_modules/ts-proto/protoc-gen-ts_proto
Para evitar buf push
de ler arquivos .proto
irrelevantes, configure buf.yaml
como assim:
Construção: exclui: [Node_modules]
Você também pode usar o plug -in oficial publicado no registro BUF.
Versão: v1plugins: -Plugin: buf.build/community/stephenh-ts-protoout: ../gen/tsopt: - outputServices = ... - useExactTypes = ...
Se você estiver usando uma configuração TS moderna com esModuleInterop
ou executando em um ambiente ESM, precisará passar por ts_proto_opt
S de:
esModuleInterop=true
se estiver usando esModuleInterop
em seu tsconfig.json
e
importSuffix=.js
se executar o código TS-proto gerado em um ambiente ESM
Em termos do código que ts-proto
gera, os objetivos gerais são:
Tipos de texto datilomático/ES6 idiomáticos
ts-proto
é uma quebra limpa do código JS de protoc
ou da abordagem " protobufjs
MAKE .d.ts
*.js
(Tecnicamente, o pacote protobufjs/minimal
é usado para realmente ler/escrever bytes.)
Descript-primeiro de saída
Interfaces nas classes
Tanto quanto possível, os tipos são apenas interfaces, para que você possa trabalhar com mensagens como hashes/estruturas de dados regulares.
Somente suporta codegen *.proto
-to- *.ts
fluxo de trabalho, atualmente sem reflexão/carregamento de tempo de execução de arquivos dinâmicos .proto
Observe que o TS-proto não é uma estrutura RPC pronta para uso; Em vez disso, é mais uma faca de braço suíço (como testemunhado por suas muitas opções de configuração), que permite criar exatamente a estrutura do RPC que você deseja em cima (ou seja, isso melhor se integra ao ecossistema protobuf da sua empresa; para melhor ou pior , o Protobuf RPC ainda é um ecossistema um pouco fragmentado).
Se você deseja uma estrutura RPC pronta para uso construída sobre o TS-Proto, existem alguns exemplos:
Nice-GRPC
Starpc
(Nota para possíveis colaboradores, se você desenvolver outras estruturas/mini-quadroworks ou até postagens/tutoriais do blog, ao usar ts-proto
, estamos felizes em vincular-se a eles.)
Também não apoiamos os clientes para o Google Cloud APIs, com sede no google.api.http
, consulte o #948 se desejar enviar um PR.
Os tipos gerados são "apenas dados", ou seja:
Interface de exportação simples { Nome: String; idade: número; Criado: Data | indefinido; Criança: Criança | indefinido; Estado: STATENUM; netos: criança []; Moedas: número [];}
Juntamente com os métodos de fábrica encode
/ decode
:
exportar const simples = { Create (BaseObject?: Deeppartial <Simple>): simples {...}, Encode (Mensagem: Simples, Writer: Writer = Writer.Create ()): Writer {...}, Decode (leitor: leitor, comprimento?: número): simples {...}, dejson (objeto: qualquer): simples {...}, FromParcial (Objeto: Deeppartial <Simple>): simples {...}, TOJSON (MENSAGEM: Simples): desconhecido {...},};
Isso permite o uso idiomático de TS/JS como:
const bytes = simples.encode ({name: ..., idade: ..., ...}). finalize (); const simples = simples.decode (leitor.create (bytes)); const {name, idade } = simples;
O que pode facilitar drasticamente a integração ao converter para/de outras camadas sem criar uma classe e chamar os getters/setters certos.
A tentativa de um homem pobre de "por favor, devolva os tipos opcionais"
Os tipos canônicos de invólucro do protobuf, ou seja, google.protobuf.StringValue
, são mapeados como valores opcionais, ou seja, string | undefined
, o que significa que, para primitivas, podemos fingir que o sistema do tipo Protobuf possui tipos opcionais.
( Atualização : TS-proto agora também suporta a palavra-chave optional
proto3.)
Timestamps são mapeados como Date
(Configurável com o parâmetro useDate
.)
fromJSON
/ toJSON
usa o formato de codificação JSON Canonical Proto3 (por exemplo, timestamps são strings ISO), ao contrário do protobufjs
.
ObjectIds pode ser mapeado como mongodb.ObjectId
(Configurável com o parâmetro useMongoObjectId
.)
(Nota: atualmente é suportado apenas pelos clientes TWIRP.)
Se você estiver usando os clientes da TS-Proto para ligar para os micro-serviços de back-end, semelhante ao problema N+1 em aplicativos SQL, é fácil para os clientes de micro-serviço (ao servir uma solicitação individual) acionar inadvertidamente várias chamadas de RPC separadas para "Get Book 1", "Get Book 2", "Get Book 3", que realmente deve ser entregue em um único "Get Books [1, 2, 3]" (assumindo que o back-end suporta um método RPC orientado a lote).
O TS-proto pode ajudar com isso e, essencialmente, lotam automaticamente suas chamadas individuais de "Get Book" em chamadas de "Get Books" em lote.
Para que o TS-proto faça isso, você precisa implementar os métodos RPC do seu serviço com a convenção de lotes de:
Um nome de método de Batch<OperationName>
O tipo de entrada Batch<OperationName>
possui um único campo repetido (ou seja, repeated string ids = 1
)
O tipo de saída Batch<OperationName>
possui a:
Um único campo repetido (ou seja, repeated Foo foos = 1
) onde a ordem de saída é a mesma que a ordem de ids
de entrada , ou
Um mapa da entrada para uma saída (ou seja, map<string, Entity> entities = 1;
)
Quando o TS-Proto reconhece métodos desse padrão, ele criará automaticamente uma versão "não-lotes" do <OperationName>
para o cliente, ou seja, client.Get<OperationName>
, que leva um único ID e retorna um único resultado.
Isso fornece o código do cliente com a ilusão de que ele pode fazer com Get<OperationName>
(que geralmente sejam preferíveis/mais fáceis ao implementar a lógica de negócios do cliente), mas a implementação real que o TS-Proto fornece acabará fazendo Batch<OperationName>
chamadas para o serviço de back -end.
Você também precisa ativar o parâmetro useContext=true
Build-time, que fornece a todos os métodos do cliente um parâmetro ctx
no estilo Go, com um método getDataLoaders
que permite que o ts-proto cache/resolva dataloador de solicitação de solicitação fundamental, o que fornece o auto-patch fundamental fundamental Comportamento de detecção/descarga.
Consulte o arquivo batching.proto
e testes relacionados para exemplos/mais detalhes.
Mas o efeito líquido é que o TS-proto pode fornecer prevenção de N+1 no estilo SQL- / ORM para chamadas de clientes, o que pode ser crítico, especialmente em implementações de alto volume / altamente paralelo, como gateways de back-end do GraphQL de alto volume, como o GraphQL, chamando micro-serviços de back-end .
ts-proto
é um plug-in protoc
, então você o executa por (diretamente em seu projeto ou mais provavelmente em seu pipeline de esquema mono-repo, ou seja, como Ibotta ou a saber):
Adicione ts-proto
ao seu package.json
Execute npm install
para baixá -lo
Invoke protoc
com um parâmetro plugin
como:
protoc --plugin = node_modules/ts-proto/protoc-gen-ts_proto ./batching.proto -i.
ts-proto
também pode ser invocado com Gradle usando o Protobuf-Gradle-Plugin:
Protobuf { plugins {// `ts` podem ser substituídos por qualquer nome de plug -in não utilizado, por exemplo, tsproto`ts { caminho = 'caminho/para/plugin'} } // Esta seção só é necessária se você fornecer opções de plug -in. all (). Cada {Task -> Task.plugins {// deve corresponder ao ID do plug -in declarado acima { opção 'foo = bar'} } } } }
O código gerado será colocado no diretório de construção gradle.
Com --ts_proto_opt=globalThisPolyfill=true
, o ts-proto incluirá um poli-preenchimento para o global.
Padrões para false
, ou seja, assumimos globalThis
está disponível.
Com --ts_proto_opt=context=true
, os serviços terão um parâmetro ctx
no estilo Go, que é útil para rastreamento/log/etc. Se você não estiver usando a API async_hooks
do Node por motivos de desempenho.
Com --ts_proto_opt=forceLong=long
, todos os números de 64 bits serão analisados como instâncias de Long
(usando a biblioteca longa).
Com --ts_proto_opt=forceLong=string
, todos os números de 64 bits serão emitidos como strings.
Com --ts_proto_opt=forceLong=bigint
, todos os números de 64 bits serão produzidos como BigInt
s. Esta opção ainda usa a biblioteca long
para codificar/decodificar internamente no protobuf.js
, mas depois se converte para/de BigInt
s no código gerado por TS-Proto.
O comportamento padrão é forceLong=number
, que ainda usará internamente a biblioteca long
para codificar/decodificar valores no fio (para que você ainda verá um util.Long = Long
linha em sua saída), mas converterá os valores long
para number
automaticamente para você. Observe que um erro de tempo de execução é lançado se, ao fazer essa conversão, um valor de 64 bits for maior do que pode ser armazenado corretamente como um number
.
Com --ts_proto_opt=useJsTypeOverride
, os números de 64 bits serão emitidos como o fieldOption.jstype especificado no campo. Isso tem precedência sobre a opção forceLong
fornecida.
Com --ts_proto_opt=esModuleInterop=true
altera a saída para ser compatível esModuleInterop
.
Especificamente, as Long
importações serão geradas como import Long from 'long'
em vez de import * as Long from 'long'
.
Com --ts_proto_opt=env=node
ou browser
ou both
, o TS-proto fará suposições específicas do ambiente em sua saída. Isso padrão é both
, o que não faz suposições específicas do ambiente.
O uso node
altera os tipos de bytes
do Uint8Array
para Buffer
para facilitar a integração com o ecossistema do nó que geralmente usa Buffer
.
Atualmente, browser
não tem nenhum comportamento específico além de ser "não node
". Provavelmente será em breve/em algum momento.
Com --ts_proto_opt=useOptionals=messages
(para campos de mensagem) ou --ts_proto_opt=useOptionals=all
(para campos de mensagem e escalar), os campos são declarados como chaves opcionais, por exemplo field?: Message
em vez do field: Message | undefined
.
ts-proto padrões para useOptionals=none
porque é:
Para a prevenção de digitação, os campos opcionais facilitam a entrada de campos extras em uma mensagem (até obtermos tipos exatos), ou seja::
Interface Somemessage { primeiro nome: string; lastName: string;} // declarado com um typeConst Data = {primeironame: "a", lastTypo: "b"}; // com useOptionals = Nenhum, isso não falha corretamente em compilar; Se o `` `` `` `` `` ”'', é o que você está sendo realizado para a vida útil.
Para uma API consistente, se SomeMessage.lastName
for Opcional lastName?
, então os leitores precisam verificar duas condições vazias: a) é lastName
undefined
(b/c foi criado na memória e deixado sem ser definido), ou b) é lastName
vazio (b/c lemos SomeMessage
fora do fio e, de acordo com a especificação Proto3, inicializou lastName
da string vazia)?
Para garantir a inicialização adequada, se mais tarde é adicionado SomeMessage.middleInitial
, mas é marcado como middleInitial?
, você pode ter muitos sites de chamadas no código de produção que agora devem estar passando middleInitial
para criar uma SomeMessage
válida, mas não são.
Portanto, entre a prevenção de digitação, a inconsistência do leitor e a inicialização adequada, o TS-Proto recomenda o uso de useOptionals=none
como a opção "mais segura".
Tudo isso dito, essa abordagem exige que os escritores/criadores defina todos os campos (embora fromPartial
e create
destinam -se a resolver isso); portanto, se você ainda deseja ter chaves opcionais, poderá definir useOptionals=messages
ou useOptionals=all
.
(Veja esta questão e esta questão para discussões sobre useOptional
.)
Evita erros de digitação ao inicializar mensagens e
Fornece a API mais consistente para os leitores
Garante que as mensagens de produção sejam adequadamente inicializadas com todos os campos.
Com --ts_proto_opt=exportCommonSymbols=false
, tipos de utilidade como DeepPartial
e protobufPackage
não serão export
d.
Isso deve possibilitar o uso da criação de importações de barril da saída gerada, ou seja, import * from ./foo
e import * from ./bar
.
Observe que, se você tiver o mesmo nome de mensagem usado em vários arquivos *.proto
, ainda obterá conflitos de importação.
Com --ts_proto_opt=oneof=unions
, um de campos oneof
será gerado como ADTS.
Veja a seção "Oneof manuseio".
Com --ts_proto_opt=unrecognizedEnumName=<NAME>
enums conterão uma chave <NAME>
com o valor da opção unrecognizedEnumValue
.
Padrões para UNRECOGNIZED
.
Com --ts_proto_opt=unrecognizedEnumValue=<NUMBER>
enums conterão uma chave fornecida pela opção unrecognizedEnumName
com o valor de <NUMBER>
.
Padrões para -1
.
Com --ts_proto_opt=unrecognizedEnum=false
não conterão uma chave de enumeração e valor não reconhecidos, conforme fornecido pelo unrecognizedEnumName
e opções unrecognizedEnumValue
.
Com --ts_proto_opt=removeEnumPrefix=true
terão o nome da enumeração removido dos membros.
FooBar.FOO_BAR_BAZ = "FOO_BAR_BAZ"
irá gerar FooBar.BAZ = "FOO_BAR_BAZ"
Com --ts_proto_opt=lowerCaseServiceMethods=true
, os nomes dos métodos dos métodos de serviço serão reduzidos/casos de camelos, ou seja, service.findFoo
em vez de service.FindFoo
.
Com --ts_proto_opt=snakeToCamel=false
, os campos serão mantidos no caso das cobras nas teclas de mensagem e nos métodos toJSON
/ fromJSON
.
snakeToCamel
também pode ser definido como _
lista de strings (vírgula é reservada como delimitada), ou seja, --ts_proto_opt=snakeToCamel=keys_json
, onde keys
incluem as chaves de mensagens e a inclusão de json
fará as teclas JSON que farão CASE CAMEL.
String vazia, ou seja, snakeToCamel=
, manterá as duas teclas de mensagens e as teclas JSON
como capa de cobra (é a mesma que snakeToCamel=false
).
Observe que, para usar o atributo json_name
, você terá que usar o json
.
O comportamento padrão é keys_json
, ou seja, ambos serão casados com camelo e json_name
será usado se definido.
Com --ts_proto_opt=outputEncodeMethods=false
, os métodos Message.encode
e Message.decode
para trabalhar com dados codificados/binários codificados por protobuf não serão emitidos.
Isso é útil se você quiser "apenas tipos apenas".
Com --ts_proto_opt=outputJsonMethods=false
, os métodos Message.fromJSON
e Message.toJSON
para trabalhar com dados codificados por JSON não serão emitidos.
Isso também é útil se você deseja "apenas tipos apenas".
Com --ts_proto_opt=outputJsonMethods=to-only
e --ts_proto_opt=outputJsonMethods=from-only
você poderá exportar apenas um entre os métodos Message.toJSON
e Message.fromJSON
.
Isso é útil se você estiver usando o TS-proto apenas para encode
ou decode
e não para ambos.
Com --ts_proto_opt=outputPartialMethods=false
, os métodos Message.fromPartial
e Message.create
para aceitar objetos parcialmente formados/literais de objeto não serão emitidos.
Com --ts_proto_opt=stringEnums=true
, os tipos de enumeração gerados serão baseados em string em vez de baseado.
Isso é útil se você deseja "apenas tipos apenas" e estiver usando um gateway GRPC REST configurado para serializar enumes como strings.
(Requer outputEncodeMethods=false
.)
Com --ts_proto_opt=outputClientImpl=false
, as implementações do cliente, ou seja, FooServiceClientImpl
, que implementam o lado do cliente (no twirp, consulte a próxima opção para interfaces de RPC grpc-web
) não serão emitidas.
Com --ts_proto_opt=outputClientImpl=grpc-web
, as implementações do cliente, ou seja, FooServiceClientImpl
, usarão a biblioteca @Improvable-Eng/Grpc-Web no tempo de execução para enviar mensagens GRPC para um backend GRPC-Web.
(Observe que isso usa apenas o tempo de execução do GRPC-Web, você não precisa usar nenhum código gerado, ou seja, a saída TS-proto substitui sua saída ts-protoc-gen
.)
Você precisará adicionar o @improbable-eng/grpc-web
e um transporte ao package.json
do seu projeto; Consulte o diretório de integration/grpc-web
para um exemplo de trabalho. Veja também o #504 para integrar com Grpc-Web-Devtools.
Com --ts_proto_opt=returnObservable=true
, o tipo de retorno de métodos de serviço será Observable<T>
em vez de Promise<T>
.
Com --ts_proto_opt=addGrpcMetadata=true
, o último argumento dos métodos de serviço aceitará o tipo de Metadata
GRPC, que contém informações adicionais com a chamada (por exemplo, tokens de acesso/etc.).
(Requer nestJs=true
.)
Com --ts_proto_opt=addNestjsRestParameter=true
, o último argumento dos métodos de serviço será um parâmetro de descanso com o tipo. Dessa forma, você pode usar decoradores personalizados que normalmente pode usar no Nestjs.
(Requer nestJs=true
.)
Com --ts_proto_opt=nestJs=true
, os padrões mudarão para gerar o Nestjs Protobuf amigáveis tipos e interfaces de serviço que podem ser usados no lado do cliente e no lado do servidor das implementações do protobuf. Consulte o Nestjs Readme para obter mais informações sobre informações e implementação.
Especificamente outputEncodeMethods
, outputJsonMethods
e outputClientImpl
serão falsos, lowerCaseServiceMethods
será verdadeiro e outputServices
serão ignorados.
Observe que addGrpcMetadata
, addNestjsRestParameter
e returnObservable
ainda serão falsos.
Com --ts_proto_opt=useDate=false
, campos do tipo google.protobuf.Timestamp
não serão mapeados para digitar Date
dos tipos gerados. Consulte Timestamp para obter mais detalhes.
Com --ts_proto_opt=useMongoObjectId=true
, campos de um tipo chamado ObjectId, onde a mensagem é construída para ter no campo chamado valor que é uma string será mapeado para digitar mongodb.ObjectId
nos tipos gerados. Isso exigirá que seu projeto instale o pacote NPM MongoDB. Consulte ObjectId para obter mais detalhes.
Com --ts_proto_opt=annotateFilesWithVersion=false
, os arquivos gerados não conterão as versões do protoc
e ts-proto
usadas para gerar o arquivo. Esta opção é normalmente definida como true
, de modo que os arquivos listem as versões usadas.
Com --ts_proto_opt=outputSchema=true
, serão geradas típicas meta que podem ser usadas posteriormente em outros geradores de código.
Com --ts_proto_opt=outputSchema=no-file-descriptor
, as tíqueas de meta serão geradas, mas não incluímos o descritor de arquivo no esquema gerado. Isso é útil se você estiver tentando minimizar o tamanho do esquema gerado.
Com --ts_proto_opt=outputSchema=const
, as tíqueas meta serão geradas as const
, permitindo acesso à segurança do tipo a todas as suas propriedades. (Funciona apenas com o TypeScript 4.9 ou acima, porque também usa o operador satisfies
). Pode ser combinado com a opção no-file-descriptor
( outputSchema=const,outputSchema=no-file-descriptor
) para não incluir o descritor de arquivo no esquema gerado.
Com --ts_proto_opt=outputTypeAnnotations=true
, cada mensagem receberá um campo $type
contendo seu nome totalmente qualificado. Você pode usar --ts_proto_opt=outputTypeAnnotations=static-only
para omiti-lo da declaração interface
, ou --ts_proto_opt=outputTypeAnnotations=optional
para torná-lo uma propriedade opcional na definição interface
. A última opção pode ser útil se você deseja usar o campo $type
para verificação do tipo de tempo de execução nas respostas de um servidor.
Com --ts_proto_opt=outputTypeRegistry=true
, o registro de tipos será gerado que pode ser usado para resolver tipos de mensagens por nome totalmente qualificado. Além disso, cada mensagem receberá um campo $type
contendo seu nome totalmente qualificado.
Com --ts_proto_opt=outputServices=grpc-js
, o TS-proto produzirá definições de serviço e os stubs de servidor / cliente no formato GRPC-JS.
Com --ts_proto_opt=outputServices=generic-definitions
, o TS-proto produzirá definições de serviço genéricas (estrutura-agnósticas). Essas definições contêm descritores para cada método com links para os tipos de solicitação e resposta, que permitem gerar stubs de servidor e cliente em tempo de execução e também geram tipos fortes para eles no horário de compilação. Um exemplo de uma biblioteca que usa essa abordagem é NICE-GRPC.
Com --ts_proto_opt=outputServices=nice-grpc
, o TS-proto produzirá stubs de servidores e clientes para nice-grpc. Isso deve ser usado em conjunto com definições genéricas, ou seja, você deve especificar duas opções: outputServices=nice-grpc,outputServices=generic-definitions
.
Com --ts_proto_opt=metadataType=Foo@./some-file
, ts-proto adicione um campo de metadados genérico (estrutura-agnóstico) à definição de serviço genérico.
Com --ts_proto_opt=outputServices=generic-definitions,outputServices=default
, o TS-proto produzirá definições genéricas e interfaces. Isso é útil se você deseja confiar nas interfaces, mas também possui alguns recursos de reflexão em tempo de execução.
Com --ts_proto_opt=outputServices=false
, ou =none
, o TS-proto não produzirá definições de serviço.
Com --ts_proto_opt=rpcBeforeRequest=true
, o ts-proto adicionará uma definição de função à definição da interface RPC com a assinatura: beforeRequest(service: string, message: string, request: <RequestType>)
. Ele também definirá automaticamente outputServices=default
. Cada um dos métodos do serviço chamará beforeRequest
antes de executar sua solicitação.
Com --ts_proto_opt=rpcAfterResponse=true
, o TS-proto adicionará uma definição de função à definição da interface RPC com a assinatura: afterResponse(service: string, message: string, response: <ResponseType>)
. Ele também definirá automaticamente outputServices=default
. Cada um dos métodos do serviço chamará afterResponse
antes de retornar a resposta.
Com --ts_proto_opt=rpcErrorHandler=true
, o TS-proto adicionará uma definição de função à definição da interface RPC com a assinatura: handleError(service: string, message: string, error: Error)
. Ele também definirá automaticamente outputServices=default
.
Com --ts_proto_opt=useAbortSignal=true
, os serviços gerados aceitarão um AbortSignal
para cancelar chamadas de RPC.
Com --ts_proto_opt=useAsyncIterable=true
, os serviços gerados usarão AsyncIterable
em vez de Observable
.
Com --ts_proto_opt=emitImportedFiles=false
, o ts-proto não emitirá arquivos google/protobuf/*
a menos que você adicione explícito arquivos a protoc
como este protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto my_message.proto google/protobuf/duration.proto
Com --ts_proto_opt=fileSuffix=<SUFFIX>
, o ts-proto emitirá arquivos gerados usando o sufixo especificado. Um arquivo helloworld.proto
com fileSuffix=.pb
seria gerado como helloworld.pb.ts
. Esse é um comportamento comum em outros plugins protoc e fornece uma maneira de globar rapidamente todos os arquivos gerados.
Com --ts_proto_opt=importSuffix=<SUFFIX>
, o TS-proto emitirá importações de arquivos usando o sufixo especificado. Uma importação de helloworld.ts
com fileSuffix=.js
geraria import "helloworld.js"
. O padrão é importar sem uma extensão de arquivo. Suportado pelo TypeScript 4.7.x e acima.
Com --ts_proto_opt=enumsAsLiterals=true
, os tipos de enumeração gerados serão objeto enum-ish com as const
.
Com --ts_proto_opt=useExactTypes=false
, os métodos gerados fromPartial
e create
não usarão tipos exatos.
O comportamento padrão é useExactTypes=true
, o que produz fromPartial
do tipo exato de uso e create
seu argumento para fazer com que o TypeScript rejeite quaisquer propriedades desconhecidas.
Com --ts_proto_opt=unknownFields=true
, todos os campos desconhecidos serão analisados e saídas como matrizes de buffers.
Com --ts_proto_opt=onlyTypes=true
, apenas tipos serão emitidos e as importações para long
e protobufjs/minimal
serão excluídas.
É o mesmo que definir outputJsonMethods=false,outputEncodeMethods=false,outputClientImpl=false,nestJs=false
Com --ts_proto_opt=usePrototypeForDefaults=true
, o código gerado envolverá novos objetos com Object.create
.
Isso permite que o código faça verificações de hazzer para detectar quando os valores padrão foram aplicados, que, devido ao comportamento do Proto3 de não colocar valores padrão no fio, geralmente é útil apenas para interagir com as mensagens Proto2.
Quando ativado, os valores padrão são herdados de um protótipo e, portanto, o código pode usar object.keys (). Inclui ("algum campo") para detectar se algum campo foi realmente decodificado ou não.
Observe que, como indicado, isso significa que o Object.Keys não incluirá campos de defasa-defasco; portanto, se você tiver código que itera as teclas de mensagens de maneira genérica, ele também terá que iterar sobre as teclas herdadas do protótipo.
Com --ts_proto_opt=useJsonName=true
, json_name
definido nos protofiles será usado em vez de nomes de campos de mensagens.
Com --ts_proto_opt=useJsonWireFormat=true
, o código gerado refletirá a representação JSON das mensagens protobuf.
Requer onlyTypes=true
. Implica useDate=string
e stringEnums=true
. Esta opção é gerar tipos que podem ser usados diretamente com mensagens protobuf de marechalling/unarshalling serializadas como JSON. Você também pode definir useOptionals=all
, pois os gateways GRPC não precisam enviar valor padrão para valores escalares.
Com --ts_proto_opt=useNumericEnumForJson=true
, o conversor JSON ( toJSON
) codificará valores de enum como int, em vez de uma string literal.
Com --ts_proto_opt=initializeFieldsAsUndefined=false
, todos os inicializadores opcionais do campo serão omitidos nas instâncias base geradas.
Com --ts_proto_opt=disableProto2Optionals=true
, todos os campos opcionais nos arquivos Proto2 não serão definidos como opcionais. Observe que esse sinalizador é principalmente para preservar o manuseio do TS-Proto de arquivos proto2 pelo TS-Proto, para evitar mudanças de quebra e, como resultado, não deve ser usado para avançar.
Com --ts_proto_opt=disableProto2DefaultValues=true
, todos os campos nos arquivos Proto2 que especificam um valor padrão não usarão esse valor padrão. Observe que esse sinalizador é principalmente para preservar o manuseio do TS-Proto de arquivos proto2 pelo TS-Proto, para evitar mudanças de quebra e, como resultado, não deve ser usado para avançar.
Com --ts_proto_opt=Mgoogle/protobuf/empty.proto=./google3/protobuf/empty
, ('m' significa 'importação', semelhante ao protoc-gen-go), o código de código gerado para ./google/protobuf/empty.ts
refletirá o valor substituído:
Mfoo/bar.proto=@myorg/some-lib
irá mapear foo/bar.proto
importa para import ... from '@myorg/some-lib'
.
Mfoo/bar.proto=./some/local/lib
irá mapear foo/bar.proto
importa para import ... from './some/local/lib'
.
Mfoo/bar.proto=some-modules/some-lib
mapear foo/bar.proto
importa para import ... from 'some-module/some-lib'
.
NOTA : Os usos são acumulados, portanto, vários valores são esperados na forma de --ts_proto_opt=M... --ts_proto_opt=M...
(um ts_proto_opt
por mapeamento).
NOTA : Os arquivos proto que correspondem às importações mapeados não serão gerados .
Com --ts_proto_opt=useMapType=true
, o código gerado para o protobuf map<key_type, value_type>
se tornará Map<key_type, value_type>
que usa o tipo de mapa JavaScript.
O comportamento padrão é useMapType=false
, o que faz com que ele gere o código para o protobuf map<key_type, value_type
com o par de valores-chave como {[key: key_type]: value_type}
.
Com --ts_proto_opt=useReadonlyTypes=true
, os tipos gerados serão declarados como imutáveis usando o modificador readonly
do TypeScript.
Com --ts_proto_opt=useSnakeTypeName=false
removerá a carcaça de cobra dos tipos.
Exemplo protobuf
caixa de mensagem {elemento da mensagem {imagem da mensagem {enum alinhamento {esquerda = 1; Centro = 2; Direita = 3; } } } }
Por padrão, isso está ativado, o que geraria um tipo de Box_Element_Image_Alignment
. Ao desativar esta opção, o tipo gerado seria BoxElementImageAlignment
.
Com --ts_proto_opt=outputExtensions=true
, o código gerado incluirá extensões proto2
Os métodos de codificação/decodificação de extensão são compatíveis com a opção outputEncodeMethods
e, se unknownFields=true
, os métodos setExtension
e getExtension
serão criados para mensagens extensíveis, também em conformidade com o outputEncodeMethods
(setExtension = code, getExtension = decodge).
Com --ts_proto_opt=outputIndex=true
, os arquivos de índice serão gerados com base nos namespaces do Proto Package.
Isso desativará exportCommonSymbols
para evitar colisões de nomes nos símbolos comuns.
Com --ts_proto_opt=emitDefaultValues=json-methods
, o método Tojson gerado emitirá escalares como 0
e ""
como campos json.
Com --ts_proto_opt=comments=false
, os comentários não serão copiados dos arquivos proto para o código gerado.
Com --ts_proto_opt=bigIntLiteral=false
, o código gerado usará BigInt("0")
em vez de 0n
para literais bigint. Os literais bigint não são suportados pelo TypeScript quando a opção "Target" Compiler definida para algo mais antigo que "ES2020".
Com --ts_proto_opt=useNullAsOptional=true
, os valores undefined
serão convertidos para null
e, se você usar o rótulo optional
no seu arquivo .proto
, o campo também terá tipo undefined
. por exemplo:
Com --ts_proto_opt=typePrefix=MyPrefix
, as interfaces, enumes e fábricas geradas terão um prefixo do MyPrefix
em seus nomes.
Com --ts_proto_opt=typeSuffix=MySuffix
, as interfaces, enumes e fábricas geradas terão um sufixo do MySuffix
em seus nomes.
Perfil de mensagemInfo {int32 id = 1; string bio = 2; string telefone = 3; } departamento de mensagens {int32 id = 1; nome da string = 2; } User de mensagens {int32 id = 1; string nome de usuário = 2;/* perfilInfo será opcional no TypeScript, o tipo será perfilInfo | nulo | Indefinido Isso é necessário nos casos em que você não deseja fornecer nenhum valor para o perfil. */Perfil de perfil opcional = 3;/* O departamento aceita apenas um tipo de departamento ou nulo; portanto, isso significa que você deve passar nulo se não houver valor disponível. */Departamento Departamento = 4; }
As interfaces geradas serão:
Exportar Interface ProfileInfo { id: número; biografia: string; Telefone: String;} departamento de interface de exportação { id: número; Nome: String;} Exportar Interface Usuário { id: número; nome de usuário: string; perfil?: perfilInfo | nulo | indefinido; // verifique este Departamento: Departamento | nulo; // Verifique este}
Com --ts_proto_opt=noDefaultsForOptionals=true
, os valores primitivos undefined
não serão inadimplentes de acordo com a especificação Protobuf. Além disso, diferentemente do comportamento padrão, quando um campo é definido como seu valor padrão padrão, ele será codificado, permitindo que ele seja enviado sobre o fio e distinguido dos valores indefinidos. Por exemplo, se uma mensagem não definir um valor booleano, normalmente, isso seria inadimplente como false
o que é diferente de ser indefinido.
Esta opção permite que a biblioteca atue de maneira compatível com a implementação do fio mantida e usada por quadrado/bloco. NOTA: Esta opção deve ser usada apenas em combinação com outro código de cliente/servidor gerado usando o fio ou o TS-proto com esta opção ativada.
Temos uma ótima maneira de trabalhar em conjunto com os Nestjs. ts-proto
gera interfaces
e decorators
para você controlador, cliente. Para mais informações, consulte o Nestjs ReadMe.
Se você deseja executar ts-proto
em todas as alterações de um arquivo proto, precisará usar uma ferramenta como Chokidar-Cli e usá-la como um script no package.json
:
"proto: generate": "protoc -ts_proto_out = ./<proto_path>/<proto_name>.proto -ts_proto_opt = Esmoduleinterop = true", "proto: watch": "chokidar" **/*. proto " - C "NPM Run Proto: Gerate" "
ts-proto
é o RPC Framework Agnóstico - como você transmite seus dados de e para sua fonte de dados, depende de você. As implementações do cliente gerado esperam um parâmetro rpc
, que tipo é definido assim:
interface RPC { Solicitação (Serviço: String, Método: String, Dados: UINT8Array): Promise <uint8Array>;}
Se você está trabalhando com o GRPC, uma implementação simples pode ficar assim:
const Conn = new Grpc.client ( "LocalHost: 8765", grpc.credentials.createInsecure ()); digite rpcimpl = (serviço: string, método: string, dados: uint8array) => prometo <uint8array>; const sendRequest: rpcimpl = (serviço, método, dados) => { // convencionalmente no GRPC, o caminho de solicitação parece // "package.names.servicename/MethodName", // Portanto, construímos uma string tão const Path = `/$ {Service}/$ {Method}`; Retorne nova promessa ((resolver, rejeitar) => {// makeUnaryRequest transmite o resultado (e erro) com um retorno de chamada // transforme isso em uma promessa! (err) {return rejeit (err); , resultadocallback); });}; const rpc: rpc = {request: sendRequest};
Parabéns aos nossos patrocinadores:
O NGROK financiou o suporte inicial da GRPC-Web da TS-Proto.
Se você precisar de personalizações TS-proto ou suporte prioritário para sua empresa, você pode me pingar por e-mail.
Esta seção descreve como contribuir diretamente para o TS-proto, ou seja, não é necessário para executar ts-proto
no protoc
ou usar o TypeRed Gerated.
Requisitos
Docker
yarn
npm install -g yarn
Configurar
Os comandos abaixo assumem que você está instalado no Docker . Se você estiver usando o OS X, instale o CoreUtils , brew install coreutils
.
Confira o repositório para obter o código mais recente.
Execute yarn install
para instalar as dependências.
Execute yarn build:test
para gerar os arquivos de teste.
Isso executa os seguintes comandos:
proto2ts
-executa ts-proto
na integration/**/*.proto
para gerar arquivos .ts
.
proto2pbjs
- gera uma implementação de referência usando pbjs
para testar compatibilidade.
Execute yarn test
Fluxo de trabalho
Adicione/atualize um teste de integração para o seu caso de uso
Você também pode deixar yarn watch
correndo, e ele deve "fazer a coisa certa"
Faça uma nova integration/your-new-test/parameters.txt
com os parâmetros ts_proto_opt
necessários
Crie um esquema mínimo integration/your-new-test/your-new-test.proto
para reproduzir seu caso de uso
Encontre um teste integration/*
próximo o suficiente para o seu caso de uso, por exemplo, um parameters.txt
que corresponde aos parâmetros ts_proto_opt
necessários para reproduzir seu caso de uso
Se criar um novo teste de integração:
Após quaisquer alterações no your-new-test.proto
, ou uma integration/*.proto
, execute yarn proto2bin
Adicione/atualize um teste integration/your-new-test/some-test.ts
, mesmo que seja tão trivial quanto apenas garantir que as compilações de código geradas
Modifique a lógica de geração de código ts-proto
:
Ou yarn proto2ts your-new-test
para re-codificar um teste específico
Mais uma vez, deixando yarn watch
que corria deve "fazer a coisa certa"
A lógica mais importante é encontrada no src/main.ts.
Após quaisquer alterações nos arquivos src/*.ts
yarn proto2ts
Execute yarn test
para verificar suas alterações, passe todos os testes existentes
Cometer e enviar um PR
Às vezes, a verificação do código gerado é desaprovada, mas, dado que o principal trabalho do TS-Proto é gerar código, ver o codegen diffs no PRS é útil
Execute yarn format
para formatar os arquivos TypeScript.
Certifique-se de git add
todos os arquivos *.proto
, *.bin
e *.ts
em integration/your-new-test
Testando em seus projetos
Você pode testar as alterações locais do TS-proto em seus próprios projetos, executando yarn add ts-proto@./path/to/ts-proto
, desde que você execute yarn build
manualmente.
Protoc do dockerizado
O repositório inclui uma versão dockerizada do protoc
, que é configurada no docker-compose.yml.
Pode ser útil caso você queira invocar manualmente o plug -in com uma versão conhecida do protoc
.
Uso:
# Inclua o alias do protoc em seu shell. Aliases.sh# Run Protoc como de costume. O diretório TS-proto está disponível em /ts-proto.protoc --plugin =/ts-proto/protoc-gen-ts_proto ---ts_proto_out =./Output -i =./Protos ./protoc/*.proto# ou Use o alias ts-protoC que especifica o caminho do plug-in para você.ts-protoC ---ts_proto_out =./output -i =./protos ./protoc/*.proto
Todos os caminhos devem ser caminhos relativos no diretório de trabalho atual do host. ../
não é permitido
Dentro do recipiente do docker, o caminho absoluto para a raiz do projeto é /ts-proto
O contêiner monta o diretório de trabalho atual em /host
e o define como seu diretório de trabalho.
Depois que aliases.sh
é adquirido, você pode usar o comando protoc
em qualquer pasta.
O nome do módulo TS/ES6 é o pacote Proto
Apoie a codificação baseada em String de duração em fromJSON
/ toJSON
Faça oneof=unions-value
o comportamento padrão em 2.0
Provavelmente altere a inadimplência forceLong
em 2.0, deve padrão para forceLong=long
Faça esModuleInterop=true
o padrão em 2.0
Por padrão, o TS-proto modela oneof
campos "categoricamente" na mensagem, por exemplo, uma mensagem como:
mensagem foo {umof oufield {string field_a = 1; string field_b = 2; } }
Irá gerar um tipo Foo
com dois campos: field_a: string | undefined;
e field_b: string | undefined
.
Com essa saída, você precisará verificar if object.field_a
e if object.field_b
, e se você definir um, precisará se lembrar de despertar o outro.
Em vez disso, recomendamos o uso da opção oneof=unions-value
, que alterará a saída para ser um tipo de dados algébrica/ADT como:
Interface YourMessage { qualquer campo?: {$ case: "field_a"; Valor: String} | {$ case: "field_b"; Valor: String};}
Como isso aplicará automaticamente apenas um dos field_a
ou field_b
"sendo definido" por vez, porque os valores são armazenados no campo eitherField
que só pode ter um único valor por vez.
(Observe que eitherField
é opcional b/c oneof
de protobuf significa "no máximo um campo" está definido e não significa que um dos campos deve ser definido.)
Na versão 2.x do TS-Proto atualmente sem intercalação, oneof=unions-value
se tornará o comportamento padrão.
Há também uma opção oneof=unions
, que gera um sindicato em que os nomes de campo são incluídos em cada opção:
Interface YourMessage { qualquer campo?: {$ case: "field_a"; campo_a: string} | {$ case: "field_b"; campo_b: string};}
Isso não é mais recomendado, pois pode ser difícil escrever código e tipos para lidar com várias opções ONEOF:
Os seguintes tipos de auxiliar podem facilitar o trabalho com os tipos gerados a partir de oneof=unions
, embora geralmente não sejam necessários se você usar oneof=unions-value
:
/** Extrai todos os nomes de casos de um campo One of. */tipo OneofCases <T> = t estende {$ case: infernde u estende a string}? U: nunca;/** extrai uma união de todos os tipos de valor de um campo One OFE*/tipo OneOfValues <T> = t estende {$ case: inferndo u estende a string; [Chave: String]: Desconhecido}? T [u]: nunca;/** Extrai o tipo específico de um caso de um de um baseado em seu nome de campo*/tipo Oneofcase <t, k estende um oneofCases <t>> = t estende { $ case: k; [Chave: String]: Desconhecido;} ? T : nunca;/** Extrair o tipo específico de um tipo de valor de um campo One OFE*/tipo OneofValue <t, k estende oneofCases <t>> = t estende { $ case: inferir u estende k; [Chave: String]: Desconhecido;} ? T [u] : nunca;
Para comparação, os equivalentes para oneof=unions-value
:
/** Extrai todos os nomes de casos de um campo One of. */tipo OneofCases <T> = t ['$ case'];/** Extrai uma união de todos os tipos de valor de um campo*/tipo Oneofvalues <T> = t ['value'];/** Extratos O tipo específico de um caso de um de um baseado em seu nome de campo */tipo Oneofcase <t, k estende oneofCases <t>> = t estende { $ case: k; [Chave: String]: Desconhecido;} ? T : nunca;/** Extrair o tipo específico de um tipo de valor de um campo One OFE*/tipo OneofValue <t, k estende oneofCases <t>> = t estende { $ case: inferir u estende k; Valor: desconhecido;} ? T [u] : nunca;
No Protobuf Core (e também ts-proto
), os valores não atendidos ou iguais ao valor padrão não são enviados sobre o fio.
Por exemplo, o valor padrão de uma mensagem é undefined
. Os tipos primitivos tomam seu valor padrão natural, por exemplo, string
é ''
, number
é 0
, etc.
O Protobuf escolheu/aplica esse comportamento porque permite a compatibilidade avançada, pois os campos primitivos sempre terão um valor, mesmo quando omitidos por agentes desatualizados.
Isso é bom, mas também significa que os valores inadimplentes e não definidos não podem ser distinguidos nos campos ts-proto
; É apenas fundamentalmente como o Protobuf funciona.
Se você precisar de campos primitivos, onde pode detectar o conjunto/não definido, consulte os tipos de wrapper.
Codificar / decodificar
ts-proto
segue as regras do Protobuf e sempre retorna valores padrão para os campos Unsets ao decodificar, enquanto os omitem da saída quando serializados em formato binário.
Syntax = "proto3"; mensagem foo {barra de string = 1; }
Protobufbytes; // Suponha que este seja um objeto Foo vazio, no protobuf binário formatfoo.decode (protobufbytes); // => {bar: ''}
Foo.Encode ({bar: ""}); // => {}, escreve um objeto vazio foo, em formato binário protobuf
Fromjson / Tojson
A leitura do JSON também inicializará os valores padrão. Como os remetentes podem omitir campos não definidos ou defini -los como o valor padrão, use fromJSON
para normalizar a entrada.
Foo.fromjson ({}); // => {bar: ''} foo.fromjson ({bar: ""}); // => {bar: ''} foo.fromjson ({bar: "baz"}); // => {bar: 'Baz'}
Ao escrever o JSON, ts-proto
normaliza as mensagens, omitindo campos e campos não definidos definidos como seus valores padrão.
Foo.tojson ({}); // => {} foo.tojson ({bar: indefinido}); // => {} foo.tojson ({bar: ""}); // => {} - Nota: omitindo o valor padrão, conforme esperadofoo.tojson ({bar: "Baz"}); // => {bar: 'Baz'}
O Protobuf vem com várias definições de mensagem predefinidas, chamadas de "tipos conhecidos". Sua interpretação é definida pela especificação do Protobuf, e espera -se que as bibliotecas convertem essas mensagens para os tipos nativos correspondentes no idioma de destino.
Atualmente, ts-proto
converte automaticamente essas mensagens em seus tipos nativos correspondentes.
Google.protobuf.BoolValue ⇆ boolean
google.protobuf.bytesvalue ⇆ Uint8Array
Google.protobuf.doubleValue ⇆ number
google.protobuf.fieldmask ⇆ string[]
Google.protobuf.floatValue ⇆ number
Google.protobuf.int32Value ⇆ number
Google.protobuf.int64Value ⇆ number
google.protobuf.listValue ⇆ any[]
Google.protobuf.uint32Value ⇆ number
Google.protobuf.uint64Value ⇆ number
Google.protobuf.stringValue ⇆ string
google.protobuf.value ⇆ any
(isto é, number | string | boolean | null | array | object
)
google.protobuf.struct ⇆ { [key: string]: any }
Os tipos de wrapper são mensagens que contêm um único campo primitivo e podem ser importados em arquivos .proto
com import "google/protobuf/wrappers.proto"
.
Como essas são mensagens , o valor padrão é undefined
, permitindo que você distingue primitivos não definidos de seus valores padrão, ao usar tipos de wrapper. ts-proto
gera esses campos como <primitive> | undefined
.
Por exemplo:
// protobufsyntax = "proto3"; importar "google/protobuf/wrappers.proto"; mensagens Examplemessage {google.protobuf.stringValue nome = 1; }
// TypeScriptInterface Examplemessage { Nome: String | indefinido;}
Ao codificar uma mensagem, o valor primitivo é convertido de volta ao seu tipo de wrapper correspondente:
Exemplemessage.Encode ({Nome: "Foo"}); // => {nome: {value: 'foo'}}, no binário
Ao ligar para Tojson, o valor não é convertido, porque os tipos de invólucros são idiomáticos no JSON.
Exemplemessage.tojson ({name: "Foo"}); // => {Nome: 'Foo'}
A linguagem e os tipos da Protobuf não são suficientes para representar todos os valores possíveis de JSON, pois o JSON pode conter valores cujo tipo é desconhecido com antecedência. Por esse motivo, o Protobuf oferece vários tipos adicionais para representar valores JSON arbitrários.
Estes são chamados de tipos de estrutura e podem ser importados em arquivos .proto
com import "google/protobuf/struct.proto"
.
google.protobuf.value ⇆ any
Este é o tipo mais geral e pode representar qualquer valor JSON (ou seja, number | string | boolean | null | array | object
).
google.protobuf.listValue ⇆ any[]
Para representar uma matriz JSON
google.protobuf.struct ⇆ { [key: string]: any }
Para representar um objeto JSON
ts-proto
se converte automaticamente entre esses tipos de estrutura e seus tipos JSON correspondentes.
Exemplo:
// protobufsyntax = "proto3"; importar "google/protobuf/struct.proto"; mensagem de mensagem {google.protobuf.value qualquer coisa = 1; }
// TypeScriptInterface Examplemessage { Qualquer coisa: qualquer | indefinido;}
A codificação de um valor JSON incorporado em uma mensagem, converte -o em um tipo de estrutura:
Examplemessage.Encode ({qualquer coisa: {name: "hello"}});/* produz a seguinte estrutura, codificada no protobuf formato binário: {qualquer coisa: value {structValue = struct {fields = [mapentry {key = "name", valor = valor {stringValue = "hello"}]}}}}*/ExemplemEssage.Encode ({qualquer coisa: true});/* produz a seguinte estrutura codificada no protobuf formato binário: {qualquer coisa: valor {boolvalue = true}}}} */
A representação do google.protobuf.Timestamp
é configurável pelo sinalizador useDate
. O sinalizador de useJsonTimestamp
controla a precisão quando useDate
é false
.
Protobuf, tipo bem conhecido | Padrão/ useDate=true | useDate=false | useDate=string | useDate=string-nano |
---|---|---|---|---|
google.protobuf.Timestamp | Date | { seconds: number, nanos: number } | string | string |
Ao usar useDate=false
e useJsonTimestamp=raw
é representado como { seconds: number, nanos: number }
, mas possui precisão de nanossegundos.
Ao usar o timestamp useDate=string-nano
é representado como uma string ISO com precisão de nanossegundos 1970-01-01T14:27:59.987654321Z
e depende da biblioteca de nano-data para conversão. Você precisará instalá -lo em seu projeto.
Os números são, por padrão, assumidos como number
de JavaScript simples s.
Isso é bom para tipos de protobuf, como int32
e float
, mas tipos de 64 bits como int64
não podem ser 100% representados pelo tipo de number
de JavaScript, porque int64
pode ter valores maiores/menores que number
.
A configuração padrão do TS-Proto (que é forceLong=number
) ainda deve usar number
para campos de 64 bits e, em seguida, lançar um erro se um valor (no tempo de execução) for maior que Number.MAX_SAFE_INTEGER
.
Se você espera usar valores de 64 bits / mais que MAX_SAFE_INTEGER
, poderá usar a opção TS-proto forceLong
, que usa o pacote NPM longo para suportar todo o intervalo de valores de 64 bits.
Os tipos de números do protobuf são mapeados para tipos de JavaScript com base na opção de configuração forceLong
:
Tipos de números Protobuf | Padrão/ forceLong=number | forceLong=long | forceLong=string |
---|---|---|---|
dobro | número | número | número |
flutuador | número | número | número |
int32 | número | número | número |
Int64 | número* | Longo | corda |
uint32 | número | número | número |
uint64 | número* | Não assinado por muito tempo | corda |
Sint32 | número | número | número |
Sint64 | número* | Longo | corda |
Fixo32 | número | número | número |
Fixo64 | número* | Não assinado por muito tempo | corda |
Sfixed32 | número | número | número |
sfixed64 | número* | Longo | corda |
Onde (*) indica que eles podem causar um erro em tempo de execução.
Primitivos necessários: use como é, ou seja, string name = 1
.
Primitives opcionais: use tipos de wrapper, isto é, StringValue name = 1
.
Mensagens necessárias: não disponível
Mensagens opcionais: use como é, ou seja, SubMessage message = 1
.