基于Typescript中的对象数组创建对象类型
我有一个用js编写的库,可以帮助打包和解包基于Typescript中的对象数组创建对象类型,typescript,Typescript,我有一个用js编写的库,可以帮助打包和解包Buffers。它使用生成器模式: const bufferFormat=buffer() .int8('id')) .int16(“子通道”) .int32(“通道”) .int32('connectionId')) .varString(“消息”); 常量buff=缓冲区。从(…); const obj=bufferFormat.unpack(buff); /* obj的类型==={ id:编号; 子通道:编号; 频道:号码; connectionI
Buffer
s。它使用生成器模式:
const bufferFormat=buffer()
.int8('id'))
.int16(“子通道”)
.int32(“通道”)
.int32('connectionId'))
.varString(“消息”);
常量buff=缓冲区。从(…);
const obj=bufferFormat.unpack(buff);
/*
obj的类型==={
id:编号;
子通道:编号;
频道:号码;
connectionId:数字;
消息:字符串;
}
*/
const buffOut=bufferFormat.pack({
id:1,
子频道:2,
连接ID:3,
消息:“消息”,
});
我想给它添加类型,理想情况下让它隐式地计算出对象类型。我考虑这样做的方式是将格式化程序从生成器样式更改为在构造函数中采用一系列格式:
type FormatArrayElement<K extends keyof any> = { name: K, type: keyof TypeMapping };
const bufferFormat=新的bufferFormat([
{
键入:“int8”,
名称:“id”,
},
{
类型:“int16”,
名称:'子频道',
},
{
键入:“字符串”,
名称:'消息',
},
]);
然后隐式地确定要保存的包/解包对象类型
接口{
id:编号;
子频道:号码,
消息:string,
}
这需要我能够从对象数组中推断对象类型。这可以用typescript实现吗?或者我必须想出另一种方法来将类型添加到此缓冲区格式化程序吗?您不必更改实现,可以将类型赋予原始生成器对象,以便编译器能够推断
解包的结果。我们在BufferBuilder
的通用参数中收集名称和二进制类型,并且unpack
使用该参数使用PropTypeMap
将其转换为对象类型:
interface PropTypeMap {
int8: number;
int16: number;
int32: number;
varString: string;
}
type PropType = keyof PropTypeMap;
interface BufferBuilder<PropTypes extends { [p in string]: PropType }> {
int8<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'int8' }>;
int16<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'int16' }>;
int32<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'int32' }>;
varString<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'varString' }>;
unpack(buffer: Buffer): { [p in keyof PropTypes]: PropTypeMap[PropTypes[p]] };
pack(obj: { [p in keyof PropTypes]: PropTypeMap[PropTypes[p]] }): Buffer;
}
declare function buffer(): BufferBuilder<{}>;
// typed implementation left as exercise
const bufferFormat = buffer()
.int8('id')
.int16('subchannel')
.int32('channel')
.int32('connectionId')
.varString('message');
const obj = bufferFormat.unpack({} as Buffer); // inferred as const obj: { id: number; subchannel: number; channel: number; connectionId: number; message: string; }
接口PropTypeMap{
int8:数字;
int16:数字;
int32:数字;
varString:string;
}
类型PropType=PropTypeMap的键;
接口缓冲生成器{
int8(n:n):缓冲区生成器;
int16(n:n):缓冲区生成器;
int32(n:n):缓冲区生成器;
varString(n:n):缓冲区生成器;
解包(buffer:buffer):{[p in-keyof-PropTypes]:PropTypeMap[PropTypes[p]};
pack(obj:{[p in-keyof-PropTypes]:PropTypeMap[PropTypes[p]}):缓冲区;
}
声明函数buffer():BufferBuilder;
//类型化实现留作练习
const bufferFormat=buffer()
.int8('id'))
.int16(“子通道”)
.int32(“通道”)
.int32('connectionId'))
.varString(“消息”);
const obj=bufferFormat.unpack({}作为缓冲区);//推断为常量对象:{id:number;子通道:number;通道:number;connectionId:number;消息:string;}
您不必更改实现,可以为原始生成器对象指定类型,以便编译器能够推断解包的结果。我们在BufferBuilder
的通用参数中收集名称和二进制类型,并且unpack
使用该参数使用PropTypeMap
将其转换为对象类型:
interface PropTypeMap {
int8: number;
int16: number;
int32: number;
varString: string;
}
type PropType = keyof PropTypeMap;
interface BufferBuilder<PropTypes extends { [p in string]: PropType }> {
int8<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'int8' }>;
int16<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'int16' }>;
int32<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'int32' }>;
varString<N extends string>(n: N): BufferBuilder<PropTypes & { [n in N]: 'varString' }>;
unpack(buffer: Buffer): { [p in keyof PropTypes]: PropTypeMap[PropTypes[p]] };
pack(obj: { [p in keyof PropTypes]: PropTypeMap[PropTypes[p]] }): Buffer;
}
declare function buffer(): BufferBuilder<{}>;
// typed implementation left as exercise
const bufferFormat = buffer()
.int8('id')
.int16('subchannel')
.int32('channel')
.int32('connectionId')
.varString('message');
const obj = bufferFormat.unpack({} as Buffer); // inferred as const obj: { id: number; subchannel: number; channel: number; connectionId: number; message: string; }
接口PropTypeMap{
int8:数字;
int16:数字;
int32:数字;
varString:string;
}
类型PropType=PropTypeMap的键;
接口缓冲生成器{
int8(n:n):缓冲区生成器;
int16(n:n):缓冲区生成器;
int32(n:n):缓冲区生成器;
varString(n:n):缓冲区生成器;
解包(buffer:buffer):{[p in-keyof-PropTypes]:PropTypeMap[PropTypes[p]};
pack(obj:{[p in-keyof-PropTypes]:PropTypeMap[PropTypes[p]}):缓冲区;
}
声明函数buffer():BufferBuilder;
//类型化实现留作练习
const bufferFormat=buffer()
.int8('id'))
.int16(“子通道”)
.int32(“通道”)
.int32('connectionId'))
.varString(“消息”);
const obj=bufferFormat.unpack({}作为缓冲区);//推断为常量对象:{id:number;子通道:number;通道:number;connectionId:number;消息:string;}
我假设您在实现方面不需要帮助;你只是想把这些类型弄清楚。像这样的怎么样
首先定义从名称(如“int16”
)到TypeScript对应类型的映射:
type TypeMapping = {
int8: number,
int16: number,
string: string,
// ... add everything you need here
}
然后描述将传递到BufferFormat
构造函数的数组元素:
type FormatArrayElement<K extends keyof any> = { name: K, type: keyof TypeMapping };
这可能有点难以消化。基本上,您使用遍历每个名称
属性,并生成由类型映射
指定的类型的值
现在,最后,我们可以声明BufferFormat
类的类型:
declare class BufferFormat<K extends keyof any, F extends FormatArrayElement<K>> {
constructor(map: F[]);
unpack(buffer: Buffer): TypeFromFormatArrayElement<F>;
pack(obj: TypeFromFormatArrayElement<F>): Buffer
}
真管用!如果您试图直接检查b
的类型,它将显示为无效类型别名:
const b: TypeFromFormatArrayElement<{
type: "int8";
name: "id";
} | {
type: "int16";
name: "subchannel";
} | {
type: "string";
name: "message";
}>
const b:TypeFromFormatArrayElement
但是如果你检查实际的属性,一切都会如你所期望的那样
希望有帮助;祝你好运 我假设您在实施方面不需要帮助;你只是想把这些类型弄清楚。像这样的怎么样
首先定义从名称(如“int16”
)到TypeScript对应类型的映射:
type TypeMapping = {
int8: number,
int16: number,
string: string,
// ... add everything you need here
}
然后描述将传递到BufferFormat
构造函数的数组元素:
type FormatArrayElement<K extends keyof any> = { name: K, type: keyof TypeMapping };
这可能有点难以消化。基本上,您使用遍历每个名称
属性,并生成由类型映射
指定的类型的值
现在,最后,我们可以声明BufferFormat
类的类型:
declare class BufferFormat<K extends keyof any, F extends FormatArrayElement<K>> {
constructor(map: F[]);
unpack(buffer: Buffer): TypeFromFormatArrayElement<F>;
pack(obj: TypeFromFormatArrayElement<F>): Buffer
}
真管用!如果您试图直接检查b
的类型,它将显示为无效类型别名:
const b: TypeFromFormatArrayElement<{
type: "int8";
name: "id";
} | {
type: "int16";
name: "subchannel";
} | {
type: "string";
name: "message";
}>
const b:TypeFromFormatArrayElement
但是如果你检查实际的属性,一切都会如你所期望的那样
希望有帮助;祝你好运 这真的很酷,我没有意识到typescript支持这种“递归”类型