ts-proto
mengubah file.proto
Anda menjadi file naskah idiomatik yang diketik dengan kuat!
Rilis 2.x-TS-Proto memigrasikan serialisasi protobuf tingkat rendah yang digunakan metode encode
dan decode
dari paket yang terhormat, tetapi penuaan & stagnan, protobufjs
ke @bufbuild/protobuf
.
Jika Anda hanya menggunakan metode encode
dan decode
, ini sebagian besar harus menjadi perubahan yang tidak melanggar.
Namun, jika Anda menggunakan kode apa pun yang menggunakan Writer
protobufjs
atau kelas Reader
lama, Anda harus memperbarui kode Anda untuk menggunakan kelas @bufbuild/protobuf
baru:
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
Jika bermigrasi ke @bufbuild/protobuf
adalah blocker untuk Anda, Anda dapat menyematkan versi ts-proto
Anda ke 1.x
Penafian & Permintaan Maaf: Saya bermaksud untuk merilis TS-Proto 2.x sebagai rilis alpha, tetapi tidak mendapatkan konfigurasi rilis semantik yang benar, dan karenanya TS-Proto 2.x diterbitkan sebagai rilis utama tanpa alpha yang tepat /siklus beta.
Jika Anda dapat mengajukan laporan (atau PR yang lebih baik!) Untuk masalah apa pun yang Anda temui saat rilis masih segar, itu akan sangat dihargai.
Tip atau trik apa pun untuk orang lain tentang migrasi juga akan dihargai!
TS-Proto
Daftar isi
Ringkasan
QuickStart
Buf
Esm
Sasaran
Non-Goals
Jenis contoh
Highlight
Pencegahan otomatis / n+1
Penggunaan
Opsi yang didukung
Dukungan NestJS
Mode menonton
Implementasi GRPC dasar
Sponsor
Perkembangan
Asumsi
Todo
Satu penanganan
Nilai default dan bidang yang tidak disetel
Tipe terkenal
Jenis pembungkus
Jenis JSON (tipe struct)
Cap waktu
Jenis Angka
Status Nilai Opsional Saat Ini
TS-Proto menghasilkan tipe naskah dari skema protobuf.
Yaitu memberi person.proto
Skema Proto seperti:
Pesan Pesan {String Name = 1; }
TS-Proto akan menghasilkan file person.ts
.
orang antarmuka { Nama: String} const Person = { encode (orang): penulis {...} decode (pembaca): orang {...} TOJSON (orang): tidak diketahui {...} fromjson (data): orang {...}}
Ia juga tahu tentang layanan dan akan menghasilkan jenis untuk mereka juga, yaitu:
Ekspor Antarmuka PingService { ping (permintaan: pingrequest): janji <pingResponse>;}
Ini juga akan menghasilkan implementasi klien PingService
; Saat ini Twirp, GRPC-WEB, GRPC-JS dan NestJ didukung.
npm install ts-proto
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. ./simple.proto
ts_proto_out
--plugin=./node_modules/.bin/protoc-gen-ts_proto
_out
Per konvensi CLI protoc
.)
Pada windows, gunakan protoc --plugin=protoc-gen-ts_proto=".node_modules.binprotoc-gen-ts_proto.cmd" --ts_proto_out=. ./simple.proto
(lihat #93)
Pastikan Anda menggunakan protoc
modern (lihat instruksi instalasi untuk platform Anda, IE protoc
v 3.0.0
tidak mendukung bendera _opt
Ini akan menghasilkan file sumber *.ts
untuk tipe *.proto
yang diberikan.
Jika Anda ingin mengemas file sumber ini ke dalam paket NPM untuk didistribusikan ke klien, cukup jalankan tsc
pada mereka seperti biasa untuk menghasilkan file .js
/ .d.ts
, dan sebarkan output sebagai paket NPM biasa.
Jika Anda menggunakan BUF, lulus strategy: all
di file buf.gen.yaml
Anda (dokumen).
Versi: V1Plugins: -Nama: tsout: ../gen/tsstrategy: allpath: ../node_modules/ts-proto/protoc-gen-ts_proto
Untuk mencegah buf push
dari membaca file .proto
yang tidak relevan, konfigurasikan buf.yaml
seperti itu:
Build: Kecuali: [node_modules]
Anda juga dapat menggunakan plugin resmi yang diterbitkan ke BUF Registry.
Versi: V1Plugins: -Plugin: buf.build/community/stephenh-ts-protoout: ../gen/tsopt: - outputServices = ... - useExactTypes = ...
Jika Anda menggunakan pengaturan TS modern dengan esModuleInterop
atau berjalan di lingkungan ESM, Anda harus lulus ts_proto_opt
S dari:
esModuleInterop=true
jika menggunakan esModuleInterop
di tsconfig.json
Anda, dan
importSuffix=.js
Jika mengeksekusi kode TS-Proto yang dihasilkan di lingkungan ESM
Dalam hal kode yang dihasilkan ts-proto
, tujuan umum adalah:
Jenis TypeTic/ES6 Idiomatik
ts-proto
adalah istirahat bersih dari kode JS protoc
Google/Java-esque bawaan atau "Make .d.ts
file komentar *.js
" dari protobufjs
(Secara teknis protobufjs/minimal
digunakan untuk benar -benar membaca/menulis byte.)
Output pertama naskah
Antarmuka di atas kelas
Sebisa mungkin, tipe hanyalah antarmuka, sehingga Anda dapat bekerja dengan pesan seperti hash/struktur data biasa.
Hanya mendukung codegen *.proto
-to- *.ts
alur kerja, saat ini tidak ada refleksi/pemuatan runtime dari file .proto
dinamis
Perhatikan bahwa TS-Proto bukanlah kerangka kerja RPC yang out-of-the-box; Alih-alih itu lebih merupakan pisau Army Swiss (seperti yang disaksikan oleh banyak opsi konfigurasi), yang memungkinkan Anda membangun kerangka kerja RPC yang Anda inginkan di atasnya (yaitu yang paling terintegrasi dengan ekosistem protobuf perusahaan Anda; baik atau buruk , Protobuf RPC masih merupakan ekosistem yang agak terfragmentasi).
Jika Anda ingin kerangka kerja RPC out-of-the-box yang dibangun di atas TS-Proto, ada beberapa contoh:
Nice-grpc
STARPC
ts-proto
Kami juga tidak mendukung klien untuk google.api.http
-Based Google Cloud API, lihat #948 jika Anda ingin mengirimkan PR.
Jenis yang dihasilkan adalah "hanya data", yaitu:
Ekspor Antarmuka Simple { Nama: String; Usia: Angka; CreateTat: Tanggal | belum diartikan; Anak: Anak | belum diartikan; Negara: Stateenum; cucu: anak []; Koin: Nomor [];}
Bersama dengan Metode Pabrik encode
/ decode
:
Ekspor const sederhana = { create (baseObject?: deeppartial <dleed>): Simple {...}, Encode (pesan: sederhana, penulis: writer = writer.create ()): penulis {...}, decode (pembaca: pembaca, panjang?: angka): sederhana {...}, fromjson (objek: any): sederhana {...}, Frompartial (objek: deeppartial <dleement>): Simple {...}, TOJSON (pesan: sederhana): tidak diketahui {...},};
Ini memungkinkan penggunaan TS/JS idiomatik seperti:
const bytes = simple.encode ({name: ..., usia: ..., ...}). finish (); const sederhana = sederhana.decode (reader.create (bytes)); const {name, usia usia } = sederhana;
Yang secara dramatis dapat memudahkan integrasi saat mengonversi ke/dari lapisan lain tanpa membuat kelas dan memanggil getters/setter yang tepat.
Upaya orang miskin untuk "tolong beri kami jenis opsional"
Jenis pembungkus protobuf kanonik, yaitu google.protobuf.StringValue
, dipetakan sebagai nilai opsional, yaitu string | undefined
, yang berarti bagi primitif kita dapat berpura -pura sistem tipe protobuf memiliki tipe opsional.
( Pembaruan : TS-Proto sekarang juga mendukung kata kunci optional
Proto3.)
Cap waktu dipetakan sebagai Date
(Dapat dikonfigurasi dengan parameter useDate
.)
fromJSON
/ toJSON
Gunakan format pengkodean Canonical JSON Canonical (misalnya cap waktu adalah string ISO), tidak seperti protobufjs
.
ObjectIds dapat dipetakan sebagai mongodb.ObjectId
(Dapat dikonfigurasi dengan parameter useMongoObjectId
.)
(Catatan: Ini saat ini hanya didukung oleh klien Twirp.)
Jika Anda menggunakan klien TS-Proto untuk memanggil backend micro-services, mirip dengan masalah N+1 dalam aplikasi SQL, mudah bagi klien layanan mikro untuk (saat melayani permintaan individu) secara tidak sengaja memicu beberapa panggilan RPC yang terpisah "Get Book 1", "Get Book 2", "Get Book 3", yang seharusnya benar-benar diharukan menjadi satu "Get Books [1, 2, 3]" (dengan asumsi backend mendukung metode RPC berorientasi batch).
TS-Proto dapat membantu dengan ini, dan pada dasarnya mengharuskan secara otomatis panggilan "Get Book" Anda menjadi panggilan "Get Books".
Agar TS-Proto melakukan ini, Anda perlu mengimplementasikan metode RPC layanan Anda dengan konvensi batching:
Nama metode Batch<OperationName>
Jenis Input Batch<OperationName>
memiliki bidang berulang tunggal (yaitu repeated string ids = 1
)
Jenis keluaran Batch<OperationName>
memiliki A:
Satu bidang berulang (yaitu repeated Foo foos = 1
) di mana urutan output sama dengan urutan input ids
, atau
Peta input ke output (yaitu map<string, Entity> entities = 1;
)
Ketika TS-Proto mengenali metode dari pola ini, itu akan secara otomatis membuat versi "non-batch" dari <OperationName>
untuk klien, yaitu client.Get<OperationName>
, yang mengambil ID tunggal dan mengembalikan satu hasil.
Ini memberikan kode klien dengan ilusi bahwa itu dapat membuat panggilan masing-masing Get<OperationName>
(yang umumnya lebih disukai/lebih mudah ketika mengimplementasikan logika bisnis klien), tetapi implementasi aktual yang disediakan TS-Proto akan berakhir membuat Batch<OperationName>
Panggilan ke layanan backend.
You also need to enable the useContext=true
build-time parameter, which gives all client methods a Go-style ctx
parameter, with a getDataLoaders
method that lets ts-proto cache/resolve request-scoped DataLoaders, which provide the fundamental auto-batch perilaku deteksi/pembilasan.
Lihat file batching.proto
dan tes terkait untuk contoh/detail lebih lanjut.
Tetapi efek bersihnya adalah bahwa TS-Proto dapat memberikan pencegahan N+1 gaya SQL- / ORM untuk panggilan klien, yang dapat menjadi penting terutama dalam implementasi volume tinggi / sangat paralel seperti gateway front-end graphql yang memanggil backend micro-services mikro .
ts-proto
adalah plugin protoc
, jadi Anda menjalankannya (baik secara langsung dalam proyek Anda, atau lebih mungkin dalam pipa skema mono-repo Anda, yaitu seperti ibotta atau yaitu):
Tambahkan ts-proto
ke package.json
Anda.json
Jalankan npm install
untuk mengunduhnya
Invoke protoc
dengan parameter plugin
seperti:
protoc --plugin = node_modules/ts-proto/protoc-gen-ts_proto ./batching.proto -i.
ts-proto
juga dapat dipanggil dengan Gradle menggunakan protobuf-gradle-plugin:
protobuf { plugin {// `ts` dapat diganti dengan nama plugin yang tidak digunakan, misalnya` tsproto`ts { path = 'path/to/plugin'} } // Bagian ini hanya diperlukan jika Anda memberikan opsi pluginGenEncePrototasks { all (). masing -masing {Task -> Task.plugins {// harus mencocokkan ID plugin yang dinyatakan di atas { opsi 'foo = bar'} } } } }
Kode yang dihasilkan akan ditempatkan di direktori Gradle Build.
Dengan --ts_proto_opt=globalThisPolyfill=true
, TS-Proto akan menyertakan polyfill untuk GlobalThis.
Default ke false
, yaitu kami menganggap globalThis
ini tersedia.
Dengan --ts_proto_opt=context=true
, Layanan akan memiliki parameter ctx
GO-gaya, yang berguna untuk melacak/logging/dll. Jika Anda tidak menggunakan API async_hooks
Node karena alasan kinerja.
Dengan --ts_proto_opt=forceLong=long
, semua angka 64-bit akan diuraikan sebagai contoh Long
(menggunakan perpustakaan panjang).
Dengan --ts_proto_opt=forceLong=string
, semua nomor 64-bit akan menjadi output sebagai string.
Dengan --ts_proto_opt=forceLong=bigint
, semua angka 64-bit akan menjadi output sebagai BigInt
s. Opsi ini masih menggunakan perpustakaan long
untuk mengkode/mendekode secara internal di dalam protobuf.js
, tetapi kemudian mengonversi ke/dari BigInt
S dalam kode yang dihasilkan TS-Proto.
Perilaku default adalah forceLong=number
, yang secara internal masih akan menggunakan pustaka long
untuk menyandikan/mendekode nilai pada kawat (jadi Anda masih akan melihat util.Long = Long
dalam output Anda), tetapi akan mengonversi nilai long
menjadi number
Secara otomatis untuk Anda. Perhatikan bahwa kesalahan runtime dilemparkan jika, saat melakukan konversi ini, nilai 64-bit lebih besar dari yang dapat disimpan dengan benar sebagai number
.
Dengan --ts_proto_opt=useJsTypeOverride
, nomor 64-bit akan menjadi output sebagai fieldoption.jstype yang ditentukan di lapangan. Ini lebih diutamakan daripada opsi forceLong
yang disediakan.
Dengan --ts_proto_opt=esModuleInterop=true
menjadi sesuai dengan esModuleInterop
.
Khususnya impor Long
akan dihasilkan sebagai import Long from 'long'
alih -alih import * as Long from 'long'
.
Dengan --ts_proto_opt=env=node
atau browser
atau both
, TS-Proto akan membuat asumsi khusus lingkungan dalam output Anda. Default ini untuk both
, yang tidak membuat asumsi khusus lingkungan.
Menggunakan node
mengubah jenis bytes
dari Uint8Array
ke Buffer
untuk integrasi yang lebih mudah dengan ekosistem simpul yang umumnya menggunakan Buffer
.
Saat ini browser
tidak memiliki perilaku spesifik selain menjadi "bukan node
". Mungkin akan segera/di beberapa titik.
Dengan --ts_proto_opt=useOptionals=messages
(untuk bidang pesan) atau --ts_proto_opt=useOptionals=all
(untuk bidang pesan dan skalar), bidang dinyatakan sebagai kunci opsional, misalnya field?: Message
alih -alih field: Message | undefined
.
TS-Proto Defaults to useOptionals=none
karena itu:
Untuk pencegahan kesalahan ketik, bidang opsional memudahkan bidang tambahan untuk masuk ke dalam pesan (sampai kita mendapatkan jenis yang tepat), yaitu:
antarmuka somemessage { FirstName: String; LastName: String;} // Dinumuskan dengan data TypoCons = {firstName: "a", lastTypo: "b"}; // dengan useOptionals = tidak ada, ini benar -benar gagal dikompilasi; Jika `lastName` adalah opsional, itu tidak akan menjadi pesan: somemessage = {... data};
Untuk API yang konsisten, jika SomeMessage.lastName
adalah lastName?
, maka pembaca harus memeriksa dua kondisi kosong: a) adalah lastName
undefined
(b/c itu dibuat dalam memori dan dibiarkan tidak disetel), atau b) adalah string kosong lastName
(b/c kita membaca SomeMessage
dari kawat dan, per per Spesifikasi Proto3, inisialisasi lastName
ke string kosong)?
Untuk memastikan inisialisasi yang tepat, middleInitial?
kemudian SomeMessage.middleInitial
, Anda mungkin memiliki banyak situs panggilan dalam kode produksi yang sekarang harus melewati middleInitial
untuk membuat SomeMessage
yang valid, tetapi tidak.
Jadi, antara pengungkapan kesalahan ketik, inkonsistensi pembaca, dan inisialisasi yang tepat, TS-Proto merekomendasikan penggunaan useOptionals=none
yang menggunakan opsi "paling aman".
Semua yang dikatakan, pendekatan ini memang membutuhkan penulis/pencipta untuk mengatur setiap bidang (walaupun fromPartial
dan create
dimaksudkan untuk mengatasi ini), jadi jika Anda masih ingin memiliki kunci opsional, Anda dapat mengatur useOptionals=messages
atau useOptionals=all
.
(Lihat masalah ini dan masalah ini untuk diskusi tentang useOptional
.)
Mencegah kesalahan ketik saat menginisialisasi pesan, dan
Memberikan API yang paling konsisten kepada pembaca
Memastikan pesan produksi diinisialisasi dengan benar dengan semua bidang.
Dengan --ts_proto_opt=exportCommonSymbols=false
, tipe utilitas seperti DeepPartial
dan protobufPackage
tidak akan export
d.
Ini harus memungkinkan untuk menggunakan impor barel dari output yang dihasilkan, yaitu import * from ./foo
dan import * from ./bar
.
Perhatikan bahwa jika Anda memiliki nama pesan yang sama yang digunakan dalam beberapa file *.proto
, Anda masih akan mendapatkan konflik impor.
Dengan --ts_proto_opt=oneof=unions
, oneof
bidang akan dihasilkan sebagai ADTS.
Lihat bagian "Oneof Handling".
Dengan --ts_proto_opt=unrecognizedEnumName=<NAME>
enums akan berisi kunci <NAME>
dengan nilai opsi unrecognizedEnumValue
.
Default untuk UNRECOGNIZED
.
Dengan --ts_proto_opt=unrecognizedEnumValue=<NUMBER>
enums akan berisi kunci yang disediakan oleh opsi unrecognizedEnumName
dengan nilai <NUMBER>
.
Default ke -1
.
Dengan --ts_proto_opt=unrecognizedEnum=false
enums tidak akan berisi kunci enum dan nilai yang tidak diakui seperti yang disediakan oleh opsi unrecognizedEnumName
dan unrecognizedEnumValue
.
Dengan --ts_proto_opt=removeEnumPrefix=true
akan menghapus nama enum dari anggota.
FooBar.FOO_BAR_BAZ = "FOO_BAR_BAZ"
akan menghasilkan FooBar.BAZ = "FOO_BAR_BAZ"
Dengan --ts_proto_opt=lowerCaseServiceMethods=true
, nama metode metode layanan akan diturunkan/kasus unta, yaitu service.findFoo
service.FindFoo
Dengan --ts_proto_opt=snakeToCamel=false
, bidang akan disimpan kasus ular di kedua tombol pesan dan metode toJSON
/ fromJSON
.
snakeToCamel
juga dapat ditetapkan sebagai daftar string yang _
(koma dipesan sebagai bendera yang dibatasi), yaitu --ts_proto_opt=snakeToCamel=keys_json
, di mana keys
akan membuat kunci pesan menjadi camel dan termasuk json
akan membuat kunci json beys menjadi kunci Kasing unta.
String kosong, IE snakeToCamel=
, akan menyimpan kedua kunci pesan dan kunci JSON
sebagai case ular (itu sama dengan snakeToCamel=false
).
Perhatikan bahwa untuk menggunakan atribut json_name
, Anda harus menggunakan json
.
Perilaku default adalah keys_json
, yaitu keduanya akan dikeluarkan unta, dan json_name
akan digunakan jika diatur.
Dengan --ts_proto_opt=outputEncodeMethods=false
, metode Message.encode
dan Message.decode
Ini berguna jika Anda ingin "hanya tipe".
Dengan --ts_proto_opt=outputJsonMethods=false
, Message.fromJSON
dan Message.toJSON
metode untuk bekerja dengan data kode JSON tidak akan menjadi output.
Ini juga berguna jika Anda ingin "hanya tipe".
Dengan --ts_proto_opt=outputJsonMethods=to-only
dan --ts_proto_opt=outputJsonMethods=from-only
Anda hanya akan dapat mengekspor satu antara metode Message.toJSON
dan Message.fromJSON
.
Ini berguna jika Anda menggunakan TS-Proto hanya untuk encode
atau decode
dan bukan untuk keduanya.
Dengan --ts_proto_opt=outputPartialMethods=false
, Message.fromPartial
Message.create
Dengan --ts_proto_opt=stringEnums=true
, tipe enum yang dihasilkan akan berbasis string alih-alih berbasis int.
Ini berguna jika Anda ingin "hanya tipe" dan menggunakan GRPC REST gateway yang dikonfigurasi untuk membuat serialisasi enum sebagai string.
(Membutuhkan outputEncodeMethods=false
.)
Dengan --ts_proto_opt=outputClientImpl=false
, implementasi klien, yaitu FooServiceClientImpl
, yang mengimplementasikan antarmuka RPC sisi klien (di TwIRP, lihat berikutnya untuk grpc-web
) antarmuka RPC tidak akan output.
Dengan --ts_proto_opt=outputClientImpl=grpc-web
, implementasi klien, yaitu FooServiceClientImpl
, akan menggunakan pustaka @musprobable-eng/grpc-web saat runtime untuk mengirim pesan GRPC ke backend GRPC-WEB.
(Perhatikan bahwa ini hanya menggunakan runtime GRPC-WEB, Anda tidak perlu menggunakan kode yang dihasilkan, yaitu output TS-Proto menggantikan output ts-protoc-gen
mereka.)
Anda harus menambahkan @improbable-eng/grpc-web
dan transportasi ke package.json
proyek Anda. Lihat Direktori integration/grpc-web
untuk contoh yang berfungsi. Juga lihat #504 untuk berintegrasi dengan GRPC-WEB-DEVTOOLS.
Dengan --ts_proto_opt=returnObservable=true
, jenis metode layanan pengembalian akan Observable<T>
alih -alih Promise<T>
.
Dengan --ts_proto_opt=addGrpcMetadata=true
, argumen terakhir dari metode layanan akan menerima jenis Metadata
GRPC, yang berisi informasi tambahan dengan panggilan (yaitu token akses/dll.).
(Membutuhkan nestJs=true
.)
Dengan --ts_proto_opt=addNestjsRestParameter=true
, argumen terakhir dari metode layanan akan menjadi parameter REST dengan tipe apapun. Dengan cara ini Anda dapat menggunakan dekorator khusus yang biasanya dapat Anda gunakan di NestJs.
(Membutuhkan nestJs=true
.)
Dengan --ts_proto_opt=nestJs=true
, default akan berubah untuk menghasilkan tipe & antarmuka servis Protobuf NestJS yang dapat digunakan dalam sisi klien dan sisi server implementasi protobuf NestJS. Lihat NestJS Readme untuk informasi lebih lanjut dan contoh implementasi.
Secara khusus outputEncodeMethods
, outputJsonMethods
, dan outputClientImpl
semuanya akan salah, lowerCaseServiceMethods
akan benar dan outputServices
akan diabaikan.
Perhatikan bahwa addGrpcMetadata
, addNestjsRestParameter
dan returnObservable
masih akan salah.
Dengan --ts_proto_opt=useDate=false
, bidang tipe google.protobuf.Timestamp
tidak akan dipetakan untuk mengetik Date
dalam tipe yang dihasilkan. Lihat cap waktu untuk lebih jelasnya.
Dengan --ts_proto_opt=useMongoObjectId=true
, bidang dari jenis yang disebut ObjectId di mana pesan dibangun untuk memiliki pada bidang yang disebut nilai yang merupakan string akan dipetakan untuk mengetik mongodb.ObjectId
dalam jenis yang dihasilkan. Ini akan membutuhkan proyek Anda untuk menginstal paket NPM MongoDB. Lihat ObjectID untuk detail lebih lanjut.
Dengan --ts_proto_opt=annotateFilesWithVersion=false
, file yang dihasilkan tidak akan berisi versi protoc
dan ts-proto
yang digunakan untuk menghasilkan file. Opsi ini biasanya diatur ke true
, sehingga file mencantumkan versi yang digunakan.
Dengan --ts_proto_opt=outputSchema=true
, pengetikan meta akan dihasilkan yang nantinya dapat digunakan dalam generator kode lain.
Dengan --ts_proto_opt=outputSchema=no-file-descriptor
, Meta Typings akan dihasilkan, tetapi kami tidak menyertakan deskriptor file dalam skema yang dihasilkan. Ini berguna jika Anda mencoba meminimalkan ukuran skema yang dihasilkan.
Dengan --ts_proto_opt=outputSchema=const
, pengetikan meta akan dihasilkan as const
, memungkinkan akses jenis-aman ke semua propertinya. (Hanya berfungsi dengan TypeScript 4.9 ke atas, karena juga menggunakan operator satisfies
). Dapat dikombinasikan dengan opsi no-file-descriptor
( outputSchema=const,outputSchema=no-file-descriptor
) untuk tidak memasukkan deskriptor file dalam skema yang dihasilkan.
Dengan --ts_proto_opt=outputTypeAnnotations=true
, setiap pesan akan diberikan bidang $type
yang berisi nama yang sepenuhnya memenuhi syarat. Anda dapat menggunakan --ts_proto_opt=outputTypeAnnotations=static-only
untuk menghilangkannya dari Deklarasi interface
, atau --ts_proto_opt=outputTypeAnnotations=optional
untuk menjadikannya properti opsional pada definisi interface
. Opsi terakhir mungkin berguna jika Anda ingin menggunakan bidang $type
untuk memeriksa jenis runtime pada respons dari server.
Dengan --ts_proto_opt=outputTypeRegistry=true
, jenis registri akan dihasilkan yang dapat digunakan untuk menyelesaikan jenis pesan dengan nama yang sepenuhnya memenuhi syarat. Juga, setiap pesan akan diberikan bidang $type
yang berisi nama yang sepenuhnya memenuhi syarat.
Dengan --ts_proto_opt=outputServices=grpc-js
, TS-Proto akan menghasilkan definisi layanan dan server / stub klien dalam format GRPC-JS.
Dengan --ts_proto_opt=outputServices=generic-definitions
, TS-Proto akan menghasilkan definisi layanan generik (kerangka kerja-agnostik). Definisi -definisi ini berisi deskriptor untuk setiap metode dengan tautan ke jenis permintaan dan respons, yang memungkinkan untuk menghasilkan server dan klien rintangan saat runtime, dan juga menghasilkan tipe yang kuat untuk mereka pada waktu kompilasi. Contoh perpustakaan yang menggunakan pendekatan ini adalah GRPC NICE.
Dengan --ts_proto_opt=outputServices=nice-grpc
, TS-PROTO akan mengeluarkan server dan stub klien untuk NICE-GRPC. Ini harus digunakan bersama dengan definisi generik, yaitu Anda harus menentukan dua opsi: outputServices=nice-grpc,outputServices=generic-definitions
.
Dengan --ts_proto_opt=metadataType=Foo@./some-file
, TS-Proto Tambahkan bidang metadata generik (framework-agnostik) ke definisi layanan generik.
Dengan --ts_proto_opt=outputServices=generic-definitions,outputServices=default
, TS-Proto akan menghasilkan definisi dan antarmuka generik. Ini berguna jika Anda ingin mengandalkan antarmuka, tetapi juga memiliki beberapa kemampuan refleksi saat runtime.
Dengan --ts_proto_opt=outputServices=false
, atau =none
, TS-Proto tidak akan mengeluarkan definisi layanan.
Dengan --ts_proto_opt=rpcBeforeRequest=true
, TS-PROTO akan menambahkan definisi fungsi ke definisi antarmuka RPC dengan tanda tangan: beforeRequest(service: string, message: string, request: <RequestType>)
. Ini juga akan secara otomatis mengatur outputServices=default
. Setiap metode layanan akan menghubungi beforeRequest
sebelum melakukan permintaannya.
Dengan --ts_proto_opt=rpcAfterResponse=true
, TS-PROTO akan menambahkan definisi fungsi ke definisi antarmuka RPC dengan tanda tangan: afterResponse(service: string, message: string, response: <ResponseType>)
. Ini juga akan secara otomatis mengatur outputServices=default
. Setiap metode layanan akan menghubungi afterResponse
sebelum mengembalikan respons.
Dengan --ts_proto_opt=rpcErrorHandler=true
, TS-Proto akan menambahkan definisi fungsi ke definisi antarmuka RPC dengan tanda tangan: handleError(service: string, message: string, error: Error)
. Ini juga akan secara otomatis mengatur outputServices=default
.
Dengan --ts_proto_opt=useAbortSignal=true
, layanan yang dihasilkan akan menerima AbortSignal
untuk membatalkan panggilan RPC.
Dengan --ts_proto_opt=useAsyncIterable=true
, layanan yang dihasilkan akan menggunakan AsyncIterable
alih -alih Observable
.
Dengan --ts_proto_opt=emitImportedFiles=false
, TS-Proto tidak akan memancarkan file google/protobuf/*
kecuali Anda menambahkan file eksplisit ke protoc
seperti protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto my_message.proto google/protobuf/duration.proto
Dengan --ts_proto_opt=fileSuffix=<SUFFIX>
, TS-Proto akan memancarkan file yang dihasilkan menggunakan akhiran yang ditentukan. File helloworld.proto
dengan fileSuffix=.pb
akan dihasilkan sebagai helloworld.pb.ts
. Ini adalah perilaku umum di plugin protok lain dan menyediakan cara untuk dengan cepat membuat semua file yang dihasilkan.
Dengan --ts_proto_opt=importSuffix=<SUFFIX>
, TS-Proto akan memancarkan impor file menggunakan akhiran yang ditentukan. Impor helloworld.ts
dengan fileSuffix=.js
akan menghasilkan import "helloworld.js"
. Standarnya adalah mengimpor tanpa ekstensi file. Didukung oleh TypeScript 4.7.x dan lebih tinggi.
Dengan --ts_proto_opt=enumsAsLiterals=true
, tipe enum yang dihasilkan akan menjadi objek enum-ish dengan as const
.
Dengan --ts_proto_opt=useExactTypes=false
, metode yang dihasilkan fromPartial
dan create
tidak akan menggunakan tipe yang tepat.
Perilaku default adalah useExactTypes=true
, yang membuat fromPartial
dan create
jenis penggunaan yang tepat untuk argumennya untuk membuat naskah menolak setiap properti yang tidak diketahui.
Dengan --ts_proto_opt=unknownFields=true
, semua bidang yang tidak diketahui akan diuraikan dan output sebagai array buffer.
Dengan --ts_proto_opt=onlyTypes=true
, hanya tipe yang akan dipancarkan, dan impor untuk long
dan protobufjs/minimal
akan dikecualikan.
Ini sama dengan pengaturan outputJsonMethods=false,outputEncodeMethods=false,outputClientImpl=false,nestJs=false
Dengan --ts_proto_opt=usePrototypeForDefaults=true
, kode yang dihasilkan akan membungkus objek baru dengan Object.create
.
Hal ini memungkinkan kode untuk melakukan pemeriksaan hazzer untuk mendeteksi kapan nilai default telah diterapkan, yang karena perilaku Proto3 tidak menempatkan nilai default pada kawat, biasanya hanya berguna untuk berinteraksi dengan pesan Proto2.
Saat diaktifkan, nilai default diwarisi dari prototipe, sehingga kode dapat menggunakan objek.keys (). Termasuk ("Somefield") untuk mendeteksi apakah Somefield benar -benar diterjemahkan atau tidak.
Perhatikan bahwa, seperti yang ditunjukkan, ini berarti objek.Keys tidak akan menyertakan bidang set-by-default, jadi jika Anda memiliki kode yang mengulangi kunci pesan secara generik, itu juga harus mengulangi kunci yang diwarisi dari prototipe.
Dengan --ts_proto_opt=useJsonName=true
, json_name
yang didefinisikan dalam protofil akan digunakan sebagai pengganti nama bidang pesan.
Dengan --ts_proto_opt=useJsonWireFormat=true
, kode yang dihasilkan akan mencerminkan representasi JSON dari pesan protobuf.
Hanya membutuhkan onlyTypes=true
. Menyiratkan useDate=string
dan stringEnums=true
. Opsi ini adalah untuk menghasilkan jenis yang dapat langsung digunakan dengan pesan protobuf marshalling/unmarshalling diserialisasi sebagai JSON. Anda mungkin juga ingin mengatur useOptionals=all
, karena gateway GRPC tidak diharuskan untuk mengirim nilai default untuk nilai skalar.
Dengan --ts_proto_opt=useNumericEnumForJson=true
, json converter ( toJSON
) akan menyandikan nilai enum sebagai int, bukan string literal.
Dengan --ts_proto_opt=initializeFieldsAsUndefined=false
, semua inisialisasi bidang opsional akan dihilangkan dari instance dasar yang dihasilkan.
Dengan --ts_proto_opt=disableProto2Optionals=true
, semua bidang opsional pada file Proto2 tidak akan diatur untuk menjadi opsional. Harap dicatat bahwa bendera ini terutama untuk melestarikan penanganan warisan TS-Proto dari file proto2, untuk menghindari perubahan perubahan, dan sebagai hasilnya, tidak dimaksudkan untuk digunakan untuk bergerak maju.
Dengan --ts_proto_opt=disableProto2DefaultValues=true
, semua bidang dalam file Proto2 yang menentukan nilai default tidak akan benar -benar menggunakan nilai default itu. Harap dicatat bahwa bendera ini terutama untuk melestarikan penanganan warisan TS-Proto dari file proto2, untuk menghindari perubahan perubahan, dan sebagai hasilnya, tidak dimaksudkan untuk digunakan untuk bergerak maju.
Dengan --ts_proto_opt=Mgoogle/protobuf/empty.proto=./google3/protobuf/empty
, ('m' berarti 'importmapping', mirip dengan protoc-gen-go), jalur impor kode yang dihasilkan untuk ./google/protobuf/empty.ts
akan mencerminkan nilai yang ditimpa:
Mfoo/bar.proto=@myorg/some-lib
akan memetakan foo/bar.proto
Impor ke import ... from '@myorg/some-lib'
.
Mfoo/bar.proto=./some/local/lib
akan memetakan impor foo/bar.proto
ke import ... from './some/local/lib'
.
Mfoo/bar.proto=some-modules/some-lib
akan memetakan foo/bar.proto
Impor ke import ... from 'some-module/some-lib'
.
Catatan : Penggunaan diakumulasikan, sehingga beberapa nilai diharapkan dalam bentuk --ts_proto_opt=M... --ts_proto_opt=M...
(satu ts_proto_opt
per pemetaan).
Catatan : File proto yang cocok dengan impor yang dipetakan tidak akan dihasilkan .
Dengan --ts_proto_opt=useMapType=true
, kode yang dihasilkan untuk map<key_type, value_type>
akan menjadi Map<key_type, value_type>
yang menggunakan jenis peta javascript.
Perilaku default adalah useMapType=false
, yang membuatnya menghasilkan kode untuk map<key_type, value_type
dengan pasangan nilai kunci seperti {[key: key_type]: value_type}
.
Dengan --ts_proto_opt=useReadonlyTypes=true
, tipe yang dihasilkan akan dinyatakan sebagai abadi menggunakan pengubah readonly
TypeScript.
Dengan --ts_proto_opt=useSnakeTypeName=false
akan menghilangkan casing ular dari jenis.
Contoh protobuf
kotak pesan {pesan pesan {pesan pesan {enum alignment {left = 1; Tengah = 2; Benar = 3; } } } }
Secara default ini diaktifkan yang akan menghasilkan jenis Box_Element_Image_Alignment
. Dengan menonaktifkan opsi ini, jenis yang dihasilkan adalah BoxElementImageAlignment
.
Dengan --ts_proto_opt=outputExtensions=true
, kode yang dihasilkan akan mencakup ekstensi proto2
Metode Extension Encode/Decode sesuai dengan opsi outputEncodeMethods
, dan jika unknownFields=true
, metode setExtension
dan getExtension
akan dibuat untuk pesan yang dapat diperpanjang, juga sesuai dengan outputEncodeMethods
(setextension = encode, getextension = decode).
Dengan --ts_proto_opt=outputIndex=true
, file indeks akan dihasilkan berdasarkan namespaces paket proto.
Ini akan menonaktifkan exportCommonSymbols
untuk menghindari tabrakan nama pada simbol umum.
Dengan --ts_proto_opt=emitDefaultValues=json-methods
, metode TOJSON yang dihasilkan akan memancarkan skalar seperti 0
dan ""
sebagai bidang JSON.
Dengan --ts_proto_opt=comments=false
, komentar tidak akan disalin dari file proto ke kode yang dihasilkan.
Dengan --ts_proto_opt=bigIntLiteral=false
, kode yang dihasilkan akan menggunakan BigInt("0")
bukan 0n
untuk literal BigInt. Bigint Literals tidak didukung oleh TypeScript ketika opsi kompiler "target" diatur ke sesuatu yang lebih tua dari "ES2020".
Dengan --ts_proto_opt=useNullAsOptional=true
, undefined
akan dikonversi menjadi null
, dan jika Anda menggunakan label optional
di file .proto
Anda, bidang akan memiliki jenis undefined
juga. Misalnya:
Dengan --ts_proto_opt=typePrefix=MyPrefix
, antarmuka yang dihasilkan, enum, dan pabrik akan memiliki awalan MyPrefix
dalam nama mereka.
Dengan --ts_proto_opt=typeSuffix=MySuffix
, antarmuka yang dihasilkan, enum, dan pabrik akan memiliki sufiks MySuffix
dalam namanya.
Profil Pesaninfo {int32 id = 1; String bio = 2; string phone = 3; } Departemen pesan {int32 id = 1; name string = 2; } Pengguna pesan {int32 id = 1; string username = 2;/* ProfileInfo akan opsional di TypeScript, jenisnya akan menjadi profilinfo | null | Tidak ditentukan Ini diperlukan dalam kasus di mana Anda tidak ingin memberikan nilai apa pun untuk profil. */Profil Opsional Profilfo Profil = 3;/* Departemen hanya menerima jenis departemen atau nol, jadi ini berarti Anda harus melewatinya nol jika tidak ada nilai yang tersedia. */Departemen departemen = 4; }
Antarmuka yang dihasilkan adalah:
Ekspor Antarmuka Profilinfo { ID: Nomor; bio: string; Telepon: String;} Ekspor Departemen Antarmuka { ID: Nomor; Nama: String;} Ekspor Pengguna Antarmuka { ID: Nomor; Nama pengguna: string; Profil?: ProfileInfo | null | belum diartikan; // periksa yang ini Departemen: Departemen | batal; // periksa yang satu ini}
Dengan --ts_proto_opt=noDefaultsForOptionals=true
dan undefined
tidak akan default sesuai spek protobuf. Selain itu tidak seperti perilaku standar, ketika suatu bidang diatur ke nilai default standar, itu akan dikodekan memungkinkannya untuk dikirim melalui kawat dan dibedakan dari nilai yang tidak ditentukan. Misalnya jika suatu pesan tidak menetapkan nilai boolean, biasanya ini akan default menjadi false
yang berbeda dengan itu tidak ditentukan.
Opsi ini memungkinkan perpustakaan untuk bertindak dengan cara yang kompatibel dengan implementasi kawat yang dikelola dan digunakan oleh persegi/blok. Catatan: Opsi ini hanya boleh digunakan dalam kombinasi dengan kode klien/server lain yang dihasilkan menggunakan kawat atau TS-Proto dengan opsi ini diaktifkan.
Kami memiliki cara yang bagus untuk bekerja sama dengan NestJs. ts-proto
menghasilkan interfaces
dan decorators
untuk pengontrol Anda, klien. Untuk informasi lebih lanjut, lihat ReadMe Nestjs.
Jika Anda ingin menjalankan ts-proto
pada setiap perubahan file proto, Anda harus menggunakan alat seperti chokidar-cli dan menggunakannya sebagai skrip di package.json
:
"Proto: Generate": "Protoc ---TS_PROTO_OUT = ./<PROTO_PATH>/<PROTO_NAME>.PROTO ---TS_PROTO_OPT = ESModuleInterop = true", "tonton": "chokidar" **/*. Proto " C "NPM Run Proto: Hasilkan" "
ts-proto
adalah RPC Framework Agnostik - Bagaimana Anda mengirimkan data Anda ke dan dari sumber data Anda terserah Anda. Implementasi klien yang dihasilkan semua mengharapkan parameter rpc
, jenis mana yang didefinisikan seperti ini:
antarmuka rpc { Permintaan (Layanan: String, Metode: String, Data: UInt8Array): Promise <uint8Array>;}
Jika Anda bekerja dengan GRPC, implementasi sederhana bisa terlihat seperti ini:
const conn = grpc.client baru ( "Localhost: 8765", grpc.credentials.createInsecure ()); type rpcImpl = (layanan: string, metode: string, data: uint8Array) => janji <uint8Array>; const sendRequest: rpcImpl = (layanan, metode, data) => { // secara konvensional di GRPC, jalur permintaan terlihat seperti // "package.names.servicename/methodname", // Karena itu kami membangun string seperti itu const path = `/$ {service}/$ {Method}`; Return New Promise ((resolve, reject) => {// makeunaryRequest mentransmisikan hasil (dan kesalahan) dengan callback // mengubah ini menjadi janji! const resultCallback: unarycallback <any any> = (err, res) => {if (err) {return reject (err);} resolve (res);}; function passthrough (argumen: any) {return argument;} // menggunakan ststhrough sebagai serialize dan deserialize functionConn.makeunaryRequest (path, passthrough, passthrough, data, data , resultCallback); });}; const rpc: rpc = {request: sendRequest};
Kudos untuk sponsor kami:
NGROK mendanai dukungan GRPC-WEB awal TS-Proto.
Jika Anda memerlukan kustomisasi TS-Proto atau dukungan prioritas untuk perusahaan Anda, Anda dapat melakukan ping saya melalui email.
Bagian ini menjelaskan cara berkontribusi langsung ke TS-Proto, yaitu tidak diperlukan untuk menjalankan ts-proto
di protoc
atau menggunakan naskah yang dihasilkan.
Persyaratan
Buruh pelabuhan
yarn
npm install -g yarn
Pengaturan
Perintah di bawah ini menganggap Anda telah menginstal Docker . Jika Anda menggunakan OS X, instal CoreUtils , brew install coreutils
.
Lihat repositori untuk kode terbaru.
Jalankan yarn install
untuk menginstal dependensi.
Jalankan yarn build:test
untuk menghasilkan file uji.
Ini menjalankan perintah berikut:
proto2ts
-Menjalankan ts-proto
pada file integration/**/*.proto
untuk menghasilkan file .ts
.
proto2pbjs
- Menghasilkan implementasi referensi menggunakan pbjs
untuk kompatibilitas pengujian.
Jalankan yarn test
Alur kerja
Tambah/Perbarui Tes Integrasi untuk Kasus Penggunaan Anda
Anda juga dapat membiarkan yarn watch
berjalan, dan itu harus "melakukan hal yang benar"
Buat integration/your-new-test/parameters.txt
dengan params ts_proto_opt
yang diperlukan
Buat integration/your-new-test/your-new-test.proto
Skema Untuk Mereproduksi Kasing Penggunaan Anda
Temukan integration/*
yang ada yang cukup dekat dengan kasus penggunaan Anda, misalnya memiliki parameters.txt
yang cocok dengan ts_proto_opt
Params yang diperlukan untuk mereproduksi kasing penggunaan Anda
Jika membuat tes integrasi baru:
Setelah perubahan apa pun pada your-new-test.proto
, yarn proto2bin
file integration/*.proto
Tambahkan/perbarui integration/your-new-test/some-test.ts
, bahkan jika itu sepele seperti hanya memastikan kode yang dihasilkan dikompilasi
Ubah logika pembuatan kode ts-proto
:
Atau yarn proto2ts your-new-test
untuk mengkodasi ulang tes tertentu
Sekali lagi meninggalkan yarn watch
harus "lakukan saja hal yang benar"
Logika terpenting ditemukan di SRC/Main.ts.
Setelah ada perubahan pada file TS yarn proto2ts
src/*.ts
Jalankan yarn test
untuk memverifikasi perubahan Anda lulus semua tes yang ada
Melakukan dan mengirimkan PR
Terkadang memeriksa kode yang dihasilkan disukai, tetapi mengingat pekerjaan utama TS-Proto adalah menghasilkan kode, melihat Codegen Diffs dalam PRS sangat membantu
Jalankan yarn format
untuk memformat file TypeScript.
Pastikan untuk git add
semua file *.proto
, *.bin
, dan *.ts
dalam integration/your-new-test
Pengujian di proyek Anda
Anda dapat menguji perubahan TS-Proto lokal Anda dalam proyek Anda sendiri dengan menjalankan yarn add ts-proto@./path/to/ts-proto
, selama Anda menjalankan yarn build
secara manual.
Protoc berlabuh
Repositori mencakup versi berlabuh dari protoc
, yang dikonfigurasi dalam docker-compose.yml.
Ini dapat berguna jika Anda ingin memohon plugin secara manual dengan versi protoc
yang diketahui.
Penggunaan:
# Sertakan Alias Protoc di Shell Anda .. Aliases.sh# Run Protoc seperti biasa. Direktori TS-Proto tersedia di /ts-proTo.protoc --plugin =/ts-proto/protoc-gen-ts_proTo ---ts_proto_out =./Output -i =./Protos ./protoc/*.proto# atau atau Gunakan alias TS-Protoc yang menentukan jalur plugin untuk Anda.ts-protoc ---ts_proto_out =./output -i =./Protos ./protoc/*.proto
Semua jalur harus berupa jalur relatif dalam direktori kerja host saat ini. ../
tidak diperbolehkan
Di dalam wadah Docker, jalur absolut ke root proyek adalah /ts-proto
Wadah memasang direktori kerja saat ini di /host
, dan menetapkannya sebagai direktori kerjanya.
Setelah aliases.sh
bersumber, Anda dapat menggunakan perintah protoc
di folder apa pun.
Nama modul TS/ES6 adalah paket proto
Dukung Pengkodean Durasi Berbasis String di fromJSON
/ toJSON
Buat oneof=unions-value
Perilaku Default di 2.0
Mungkin mengubah forceLong
default di 2.0, harus default menjadi forceLong=long
Buat esModuleInterop=true
default di 2.0
Secara default, TS-Proto memodelkan oneof
bidang "datar" dalam pesan, misalnya pesan seperti:
pesan foo {oneof out_field {string field_a = 1; String field_b = 2; } }
Akan menghasilkan tipe Foo
dengan dua bidang: field_a: string | undefined;
dan field_b: string | undefined
.
Dengan output ini, Anda harus memeriksa baik if object.field_a
dan if object.field_b
, dan jika Anda mengaturnya, Anda harus ingat untuk membuka yang lain.
Sebagai gantinya, kami sarankan menggunakan opsi oneof=unions-value
, yang akan mengubah output menjadi tipe data aljabar/ADT seperti:
Antarmuka YourMessage { soundfield?: {$ case: "field_a"; Nilai: String} | {$ case: "field_b"; Nilai: String};}
Karena ini akan secara otomatis menegakkan hanya satu dari field_a
atau field_b
"diatur" pada suatu waktu, karena nilai -nilainya disimpan di bidang eitherField
yang hanya dapat memiliki nilai tunggal pada satu waktu.
(Perhatikan bahwa eitherField
dari Opsional B/C oneof
dalam Protobuf berarti "paling banyak satu bidang" ditetapkan, dan tidak berarti salah satu bidang harus diatur.)
Dalam rilis 2.x yang saat ini dikeluarkan TS-Proto, oneof=unions-value
akan menjadi perilaku default.
Ada juga opsi oneof=unions
, yang menghasilkan serikat di mana nama lapangan termasuk dalam setiap opsi:
Antarmuka YourMessage { soundfield?: {$ case: "field_a"; Field_a: String} | {$ case: "field_b"; field_b: string};}
Ini tidak lagi direkomendasikan karena sulit untuk menulis kode dan tipe untuk menangani beberapa opsi satu dari:
Jenis helper berikut dapat memudahkan untuk bekerja dengan jenis yang dihasilkan dari oneof=unions
, meskipun mereka umumnya tidak diperlukan jika Anda menggunakan oneof=unions-value
:
/** mengekstrak semua nama kasus dari bidang satu. */type oneOfcases <T> = t meluas {$ case: infer u memperluas string}? U: tidak pernah;/** mengekstrak serikat dari semua jenis nilai dari bidang oneof*/type oneOfValues <T> = t meluas {$ case: infer u memperluas string; [Kunci: String]: Tidak Diketahui}? T [u]: tidak pernah;/** mengekstrak jenis spesifik dari case satu berdasarkan nama bidangnya*/type oneofcase <t, k memperluas satuofcases <t>> = t memperluas { $ case: k; [kunci: string]: tidak diketahui;} ? T : tidak pernah;/** mengekstrak jenis spesifik dari jenis nilai dari bidang oneof*/type oneOfValue <t, k memperluas OneOfcases <T>> = T meluas { $ case: infer u memperpanjang k; [kunci: string]: tidak diketahui;} ? T [u] : tidak pernah;
Sebagai perbandingan, ekuivalen untuk oneof=unions-value
:
/** mengekstrak semua nama kasus dari bidang satu. */type oneOfcases <T> = t ['$ case'];/** Mengekstrak serikat dari semua jenis nilai dari bidang ONEOF*/ketik OneOfValues <T> = t ['value'];/** Ekstrak Jenis spesifik dari satu kasus berdasarkan nama bidangnya */type oneofcase <t, k memperluas satuofcases <t>> = t meluas { $ case: k; [kunci: string]: tidak diketahui;} ? T : tidak pernah;/** mengekstrak jenis spesifik dari jenis nilai dari bidang oneof*/type oneOfValue <t, k memperluas OneOfcases <T>> = T meluas { $ case: infer u memperpanjang k; Nilai: Tidak Diketahui;} ? T [u] : tidak pernah;
Dalam protobuf inti (dan juga ts-proto
), nilai-nilai yang tidak disetel atau sama dengan nilai default tidak dikirim melalui kawat.
Misalnya, nilai default suatu pesan undefined
. Jenis primitif mengambil nilai default alami, misalnya string
adalah ''
, number
adalah 0
, dll.
Protobuf memilih/menegakkan perilaku ini karena memungkinkan kompatibilitas ke depan, karena bidang primitif akan selalu memiliki nilai, bahkan ketika dihilangkan oleh agen yang sudah ketinggalan zaman.
Ini bagus, tetapi juga berarti nilai default dan yang tidak disetel tidak dapat dibedakan dalam bidang ts-proto
; Pada dasarnya hanya bagaimana protobuf bekerja.
Jika Anda memerlukan bidang primitif di mana Anda dapat mendeteksi set/tidak ada, lihat jenis pembungkus.
Encode / Decode
ts-proto
mengikuti aturan protobuf, dan selalu mengembalikan nilai default untuk bidang yang tidak beres saat mendekodekan, sambil menghilangkannya dari output saat serial dalam format biner.
sintaks = "proto3"; pesan foo {string bar = 1; }
Protobufbytes; // Asumsikan ini adalah objek foo kosong, dalam protobuf biner formatFoo.decode (protobufbytes); // => {bar: ''}
Foo.encode ({bar: ""}); // => {}, tulis objek foo kosong, dalam format biner protobuf
Fromjson / Tojson
Membaca JSON juga akan menginisialisasi nilai default. Karena pengirim dapat menghilangkan bidang yang tidak disetel, atau mengaturnya ke nilai default, gunakan fromJSON
untuk menormalkan input.
Foo.fromjson ({}); // => {bar: ''} foo.fromjson ({bar: ""}); // => {bar: ''} foo.fromjson ({bar: "baz"}); // => {bar: 'baz'}
Saat menulis JSON, ts-proto
menormalkan pesan dengan menghilangkan bidang dan bidang yang tidak disetel yang diatur ke nilai default mereka.
Foo.toJson ({}); // => {} foo.toJson ({bar: tidak terdefinisi}); // => {} foo.toJson ({bar: ""}); // => {} - Catatan: Menghilangkan nilai default, sebagai diharapkanfoo.toJson ({bar: "baz"}); // => {bar: 'baz'}
Protobuf hadir dengan beberapa definisi pesan yang telah ditentukan, yang disebut "tipe terkenal". Interpretasi mereka ditentukan oleh spesifikasi protobuf, dan perpustakaan diharapkan untuk mengubah pesan -pesan ini menjadi tipe asli yang sesuai dalam bahasa target.
ts-proto
saat ini secara otomatis mengonversi pesan-pesan ini ke tipe asli yang sesuai.
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
(yaitu number | string | boolean | null | array | object
)
google.protobuf.struct ⇆ { [key: string]: any }
Jenis pembungkus adalah pesan yang berisi bidang primitif tunggal, dan dapat diimpor dalam file .proto
dengan import "google/protobuf/wrappers.proto"
.
Karena ini adalah pesan , nilai defaultnya undefined
, memungkinkan Anda untuk membedakan primitif yang tidak disetel dari nilai defaultnya, saat menggunakan tipe pembungkus. ts-proto
menghasilkan bidang-bidang ini sebagai <primitive> | undefined
.
Misalnya:
// protobufsyntax = "proto3"; import "google/protobuf/wrappers.proto"; pesan exampeplemessage {google.protobuf.stringValue name = 1; }
// TypeScriptInterface exampleMessage { Nama: String | belum diartikan;}
Saat mengkode pesan, nilai primitif dikonversi kembali ke tipe pembungkusnya yang sesuai:
ExampleMessage.encode ({name: "foo"}); // => {name: {value: 'foo'}}, dalam biner
Saat memanggil Tojson, nilainya tidak dikonversi, karena jenis pembungkus idiomatik di JSON.
ExampleMessage.toJson ({name: "foo"}); // => {name: 'foo'}
Bahasa dan tipe Protobuf tidak cukup untuk mewakili semua nilai JSON yang mungkin, karena JSON mungkin berisi nilai -nilai yang jenisnya tidak diketahui sebelumnya. Untuk alasan ini, Protobuf menawarkan beberapa jenis tambahan untuk mewakili nilai JSON yang sewenang -wenang.
Ini disebut tipe struct, dan dapat diimpor dalam file .proto
dengan import "google/protobuf/struct.proto"
.
google.protobuf.value ⇆ any
Ini adalah tipe yang paling umum, dan dapat mewakili nilai JSON apa pun (yaitu number | string | boolean | null | array | object
).
google.protobuf.listValue ⇆ any[]
Untuk mewakili array JSON
google.protobuf.struct ⇆ { [key: string]: any }
Untuk mewakili objek json
ts-proto
secara otomatis mengonversi bolak-balik antara tipe struct ini dan tipe JSON yang sesuai.
Contoh:
// protobufsyntax = "proto3"; import "google/protobuf/struct.proto"; pesan exampeplemessage {google.protobuf.value apa saja = 1; }
// TypeScriptInterface exampleMessage { apa saja: apapun | belum diartikan;}
Mengkode nilai JSON yang tertanam dalam pesan, mengubahnya menjadi jenis struct:
Exexplemessage.encode ({apapun: {name: "hello"}});/* output struktur berikut, dikodekan dalam format biner protobuf: {apapun: value {structValue = struct {fields = [mapentry {key = "name", value = value {stringValue = "hello"}]}}}}*/exexplemessage.encode ({apapun: true});/* output struktur berikut yang dikodekan dalam format biner protobuf: {apapun: value {boolvalue = true}} */
Representasi google.protobuf.Timestamp
dapat dikonfigurasi oleh bendera useDate
. Bendera useJsonTimestamp
mengontrol presisi saat useDate
adalah false
.
Jenis Protobuf yang terkenal | Default/ useDate=true | useDate=false | useDate=string | useDate=string-nano |
---|---|---|---|---|
google.protobuf.Timestamp | Date | { seconds: number, nanos: number } | string | string |
Saat menggunakan useDate=false
dan useJsonTimestamp=raw
direpresentasikan sebagai { seconds: number, nanos: number }
, tetapi memiliki presisi nanosecond.
Saat menggunakan useDate=string-nano
direpresentasikan sebagai string ISO dengan presisi nanosecond 1970-01-01T14:27:59.987654321Z
dan bergantung pada perpustakaan nano-date untuk konversi. Anda harus menginstalnya di proyek Anda.
Angka secara default diasumsikan sebagai number
javascript sederhana s.
Ini baik untuk jenis protobuf seperti int32
dan float
, tetapi jenis 64-bit seperti int64
tidak dapat 100% diwakili oleh tipe number
JavaScript, karena int64
dapat memiliki nilai yang lebih besar/lebih kecil dari number
.
Konfigurasi default TS-Proto (yang forceLong=number
) adalah untuk tetap menggunakan number
untuk bidang 64-bit, dan kemudian melempar kesalahan jika nilai (saat runtime) lebih besar dari Number.MAX_SAFE_INTEGER
.
Jika Anda berharap menggunakan nilai 64-bit / lebih tinggi dari MAX_SAFE_INTEGER
, maka Anda dapat menggunakan opsi forceLong
TS-Proto, yang menggunakan paket NPM panjang untuk mendukung seluruh rentang nilai 64-bit.
Peta Jenis Nomor Protobuf ke JavaScript berdasarkan opsi forceLong
Config:
Jenis Angka Protobuf | Default/ forceLong=number | forceLong=long | forceLong=string |
---|---|---|---|
dobel | nomor | nomor | nomor |
mengambang | nomor | nomor | nomor |
int32 | nomor | nomor | nomor |
int64 | nomor* | Panjang | rangkaian |
uint32 | nomor | nomor | nomor |
uint64 | nomor* | Tidak ditandatangani lama | rangkaian |
Sint32 | nomor | nomor | nomor |
Sint64 | nomor* | Panjang | rangkaian |
fixed32 | nomor | nomor | nomor |
fixed64 | nomor* | Tidak ditandatangani lama | rangkaian |
Sfixed32 | nomor | nomor | nomor |
Sfixed64 | nomor* | Panjang | rangkaian |
Di mana (*) menunjukkan mereka mungkin melakukan kesalahan saat runtime.
Diperlukan primitif: Gunakan AS-IS, yaitu string name = 1
.
Primitif opsional: Gunakan tipe pembungkus, yaitu StringValue name = 1
.
Pesan yang Diperlukan: Tidak Tersedia
Pesan Opsional: Gunakan AS-IS, yaitu SubMessage message = 1
.