Show HN: 无需代码生成,无需编译:从 Protobufs 推断 TypeScript 类型
`protobuf-ts-types` 允许开发者使用 `proto` 定义语言无关的 `message` 类型,并直接推断出 TypeScript 类型,无需代码生成或编译。通过 `pbt.infer` 函数,可以从 `proto` 源代码字符串中提取并映射 `message` 类型。文章提供了使用示例,展示了如何定义 `Person` 和 `Group` 类型,并演示了类型检查。但该项目仍处于概念验证阶段,存在一些限制,例如不支持 `service`、`rpc`、`oneof` 和 `map` 字段,以及 `import` 功能。
protobuf-ts-types
允许你用 proto
格式定义语言无关的 message
类型,然后无需额外代码生成,即可从中推断出 TypeScript 类型。
Try on github.dev | View on CodeSandbox
警告: 这只是一个概念验证,尚未准备好用于生产环境。更多细节请参考下面的 Limitations 部分。
用法
首先,安装这个包。
npm install https://github.com/nathanhleung/protobuf-ts-types
然后,在 TypeScript 中使用它。
import { pbt } from "protobuf-ts-types";
const proto = `
syntax = "proto3";
message Person {
string name = 1;
int32 id = 2;
bool is_ceo = 3;
optional string description = 4;
}
message Group {
string name = 1;
repeated Person people = 2;
}
`;
// `Proto` 是 message 名称到 message 类型的映射,从上面的 `proto` 源代码字符串推断而来。
type Proto = pbt.infer<typeof proto>;
type Person = Proto["Person"];
type Person2 = pbt.infer<typeof proto, "Person">;
// `Person` 和 `Person2` 是相同的类型:
// ```
// {
// name: string;
// id: number;
// is_ceo: boolean;
// description?: string;
// }
// ```
type Group = pbt.infer<typeof proto, "Group">;
function greetPerson(person: Person) {
console.log(`Hello, ${person.name}!`);
if (person.description) {
console.log(`${person.description}`);
} else {
console.log("(no description)");
}
}
function greetGroup(group: Group) {
console.log(`=========${"=".repeat(group.name.length)}===`);
console.log(`= Hello, ${group.name}! =`);
console.log(`=========${"=".repeat(group.name.length)}===`);
for (const person of group.people) {
greetPerson(person);
console.log();
}
}
// 如果 `Group` 或任何单个 `Person` 的结构与类型不匹配,TypeScript 将显示错误。
greetGroup({
name: "Hooli",
people: [
{
name: "Gavin Belson",
id: 0,
is_ceo: true,
description: "CEO of Hooli",
},
{
name: "Richard Hendricks",
id: 1,
is_ceo: true,
description: "CEO of Pied Piper",
},
{
name: "Dinesh Chugtai",
id: 2,
is_ceo: false,
description: "Software Engineer",
},
{
name: "Jared Dunn",
id: 3,
is_ceo: false,
},
],
});
// 输出:
// ```
// =================
// = Hello, Hooli! =
// =================
// Hello, Gavin Belson!
// CEO of Hooli
//
// Hello, Richard Hendricks!
// CEO of Pied Piper
//
// Hello, Dinesh Chugtai!
// Software Engineer
//
// Hello, Jared Dunn!
// (no description)
// ```
Limitations
- 如果不是使用内联(即 TypeScript 中的字面量)proto
string
sas const
,可能需要ts-patch
compiler patch 来导入.proto
文件,直到 microsoft/TypeScript#42219 被解决。 - 不支持
service
和rpc
(只支持message
) - 不支持
oneof
和map
字段 - 不支持
import
(目前,可以进行连接)
API
pbt
顶层导出的命名空间。
import { pbt } from "protobuf-ts-types";
pbt.infer<Proto extends string, MessageName extends string = "">
给定一个 proto 源代码字符串,推断源代码中 message
的类型。
返回值
- 如果
MessageName
是一个空字符串,则返回的类型是从 message 名称到 message 类型的映射。 - 如果
MessageName
是一个已知的message
,则返回的类型是给定MessageName
的推断类型。 - 如果
MessageName
不是一个已知的message
,则返回的类型是never
。