gpt4 book ai didi

typescript - 编译器移除 'this' 上下文类型约束

转载 作者:行者123 更新时间:2023-12-04 12:53:08 25 4
gpt4 key购买 nike

我最近构建了一个 Builder类,我意识到一些字段应该是强制性的,然后将构建器链与最终 execute() 联系起来。 .
我认为这个检查可以在编译时静态完成,因此我想出了这个解决方案(为了示例而简化):

interface abc {
a: string; // required
b: string; // required
c: string; // optional
}

class Builder<T = void> {
protected state: T = {} as any; // necessary ugly cast

public a(aa: string): Builder<T & Pick<abc, 'a'>> {
Object.defineProperty(this.state, 'a', {
value: aa,
writable: true,
});
return this as unknown as Builder<T & Pick<abc, 'a'>>;
}

public b(bb: string): Builder<T & Pick<abc, 'b'>> {
Object.defineProperty(this.state, 'b', {
value: bb,
writable: true,
});
return this as unknown as Builder<T & Pick<abc, 'b'>>;
}

public c(cc: string): Builder<T & Pick<abc, 'c'>> {
Object.defineProperty(this.state, 'c', {
value: cc,
writable: true,
});
return this as unknown as Builder<T & Pick<abc, 'c'>>;
}

public execute(this: Builder<Pick<abc, 'a' | 'b'>>) {
return this.state;
}
}
现在,当我这样做时:
new Builder().a('foo').c('bar').execute();
我得到了我想要的错误,即: The 'this' context of type ... is not assignable to method's 'this' of type ... ,这正是我想要的。
但是,当我编译此 typescript 代码并在另一个项目中导入构建文件时,我不再收到此错误。
这是编译后的类型定义:
interface abc {
a: string;
b: string;
c: string;
}
declare class Builder<T> {
protected state: T;
a(aa: string): Builder<T & Pick<abc, 'a'>>;
b(bb: string): Builder<T & Pick<abc, 'b'>>;
c(cc: string): Builder<T & Pick<abc, 'c'>>;
execute(this: Builder<Pick<abc, 'a' | 'b'>>): Pick<abc, "a" | "b">;
}
这是我的 tsconfig.json (我已经排除了项目路径以保持与主题相关):
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"strict": true,
"importHelpers": true,
"declaration": true,
"declarationDir": "dist/esm/types/",
"moduleResolution": "node",
"experimentalDecorators": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"noImplicitAny": true,
"lib": [
"ESNext",
"webworker",
"DOM"
]
}
}
雪上加霜的是,当鼠标悬停在变量上时,IntelliSense 会向我显示这些类型(尽管我知道这不一定与编译器相关):
new Builder().execute(); // should be an error
// with the type...
Builder<void>.send(this: Builder<Pick<abc, "a" | "b">>): ...
这是预期的行为吗?我需要更改 tsconfig.json 吗?难道我做错了什么?如果我不编译该类,那么它就可以完美运行。

最佳答案

你应该知道这条线是不安全的:protected state: T = {} as any; .
请考虑这种方法:


class Builder {
state = {}

public a<Param extends string>(aa: Param) {
Object.assign(this.state, { a: aa })

return this as this & { state: { a: Param } }
}

public b<Param extends string>(bb: Param) {
Object.assign(this.state, { b: bb })

return this as this & { state: { b: Param } }
}

public c<Param extends string>(cc: Param) {
Object.assign(this.state, { c: cc })

return this as this & { state: { c: Param } }
}

public execute() {
return this.state;
}
}

new Builder().a('foo').state.a // foo

new Builder().a('foo').b('bar').state.b // bar

Playground

关于typescript - 编译器移除 'this' 上下文类型约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69571387/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com