Typescript 基于调用的方法更改类型

Typescript 基于调用的方法更改类型,typescript,typescript-generics,Typescript,Typescript Generics,我有一个类,它应该允许您使用链接解析缓冲区 类解析器{ 专用缓冲区:缓冲区; 专用偏移量:数字; 私人varsInternal:记录; 构造函数(缓冲区:缓冲区){ 这个偏移量=0; this.buffer=缓冲区; this.varsInternal={}; } char(名称:string):这个{ const val=this.buffer.readUInt8(this.offset); this.varsInternal[name]=val; 该偏移量+=1; 归还这个; } short

我有一个类,它应该允许您使用链接解析
缓冲区

类解析器{
专用缓冲区:缓冲区;
专用偏移量:数字;
私人varsInternal:记录;
构造函数(缓冲区:缓冲区){
这个偏移量=0;
this.buffer=缓冲区;
this.varsInternal={};
}
char(名称:string):这个{
const val=this.buffer.readUInt8(this.offset);
this.varsInternal[name]=val;
该偏移量+=1;
归还这个;
}
short(名称:string):这个{
const val=this.buffer.readUInt16BE(this.offset);
this.varsInternal[name]=val;
该偏移量+=2;
归还这个;
}
vars():T{
将此文件退回。varsInternal;
}
}
所以你能做的是:

const data=new解析器(myBuffer)
.char(“myChar”)
.char(“其他char”)
.short(“myShort”)
.vars();
console.log(数据);//{myChar:32,otherChar:123,myShort:123544}
但我必须为此手动编写类型:

const data=new解析器(myBuffer)
.char(“myChar”)
.char(“其他char”)
.short(“myShort”)
.vars();
log(data.myChar);
//^^^^^^^不存在
const data2=新解析器(myBuffer)
.char(“myChar”)
.char(“其他char”)
.short(“myShort”)
.vars();
console.log(data.myChar);//作品
你可以看到这变得很难看


因此,我想知道是否有可能写入
char
short
的返回值,告诉TypeScript每次我链接
char
short
时,
vars
都会添加一个字段。一个可能的想法是每次添加新财产。在本例中,
T
是表示整个
记录
数据结构的类型

class Parser<T extends Record<string, number> = Record<string, number>> {
    private buffer: Buffer;
    private offset: number;
    private varsInternal: T

    constructor(buffer: Buffer) {
        this.offset = 0;
        this.buffer = buffer;
        this.varsInternal = {} as T;
    }

    char<K extends string>(name: K): Parser<T & Record<K, number>> {
        const val = this.buffer.readUInt8(this.offset); // returns number
        this.varsInternal[name] = val;
        this.offset += 1;
        return this as Parser<T & Record<K, number>>
    }

    // change short method analogue to char above

    vars() {
        return this.varsInternal;
    }
}

让我们设计一个类型别名
AddProp
,它接受一个对象类型
T
、一个键类型
K
、一个值类型
V
,并生成一个包含
T
中所有属性的新对象类型,以及一个包含键
K
和值
V
的新属性。这里有一种定义它的方法:

type AddProp<T, K extends PropertyKey, V> =
    (T & { [P in K]: V }) extends infer O ? { [P in keyof O]: O[P] } : never;
这里我将
T
的值设置为空对象类型
{}
。我们希望
varsInternal
的类型为
T
,并且我们必须确保
varsInternal
的初始值
{}
T
匹配(如果您在
新解析器(缓冲区)
中手动指定
T
,那么就不要这样做)


现在,让我们添加一个要重用的私有方法,该方法将向this.varsInternal添加一个键类型为
K
且值类型为
V
的属性,并返回
this
,其中我们断言返回的
this
将是
解析器的类型,我删除了我的评论,因为我可以在您的示例代码中看到
number
,因为返回类型在方法上是已知的,而不是使用
any
,使用
Record
会更好,除了这是一个简洁的解决方案之外。@Eldar很好的回答,似乎OP希望
number
在这里作为记录值类型(更新的答案)。对于
char
方法,它应该是
string
,对于简称方法,它应该是
number
等。是的,这取决于它将如何进一步处理。对于这个解析器类的范围,
number
似乎就足够了,因为所有示例值和类型都使用它。
type AddProp<T, K extends PropertyKey, V> =
    (T & { [P in K]: V }) extends infer O ? { [P in keyof O]: O[P] } : never;
class Parser<T = {}> {
    private buffer: Buffer;
    private offset: number;
    private varsInternal: T;

    constructor(buffer: Buffer) {
        this.offset = 0;
        this.buffer = buffer;
        this.varsInternal = {} as T;
    }
    private addProp<K extends PropertyKey, V>(prop: K, val: V): Parser<AddProp<T, K, V>> {
        (this.varsInternal as any)[prop] = val;
        return this as any;
    }
    char<K extends PropertyKey>(name: K) {
        const val = this.buffer.readUInt8(this.offset);
        const ret = this.addProp(name, val);
        this.offset += 1;
        return ret;
    }

    short<K extends PropertyKey>(name: K) {
        const val = this.buffer.readUInt16BE(this.offset);
        const ret = this.addProp(name, val);
        this.offset += 2;
        return ret;
    }
    vars(): T {
        return this.varsInternal;
    }
}
declare const myBuffer: Buffer;

const data = new Parser(myBuffer)
    .char("myChar")
    .char("otherChar")
    .short("myShort")
    .vars();
/* const data: {
    myChar: number;
    otherChar: number;
    myShort: number;
}*/

console.log(data.myChar); // number