typescript - 为什么在推断“this”的类型与显式接收它时,这种映射/条件类型的行为会有所不同?
问题描述
考虑以下代码,它使用v2.8 中引入的TypeScript 语言功能(条件类型):
type P<TObject, TPropertySuperType> = {
[K in keyof TObject]: TObject[K] extends TPropertySuperType ? K : never;
}[keyof TObject];
function g<
T,
K extends keyof Pick<T, P<T, string>>
>(obj: T, prop: K): void { }
class C {
public alpha: string;
public beta: number;
public f(): void {
g(this, "alpha"); // <-- does not compile!
g(this, "beta");
g<C, "alpha">(this, "alpha");
g<C, "beta">(this, "beta");
g(new C(), "alpha");
g(new C(), "beta");
this.g2("alpha");
this.g2("beta");
this.g2<"alpha">("alpha");
this.g2<"beta">("beta");
}
public g2<
K extends keyof Pick<C, P<C, string>>
>(prop: K) { }
}
类型背后的想法P
是它选择满足属性类型扩展的约束的属性名称。函数然后在类型参数约束中使用类型,例如:TObject
TPropertySuperType
g
g2
P
- 您只能
g
在prop
参数是extends string
类型属性的名称时调用obj
- 您只能
g2
在prop
参数是 的extends string
-typed 属性的名称时调用C
。
在这里,因为C.alpha
is of typestring
和C.beta
is of type number
,我希望g
/ g2
with的所有五次调用prop === "alpha"
都能编译,而所有五次 with 的调用都prop === "beta"
不能编译。
但是,调用g(this, "alpha")
不会编译,如果您将此代码粘贴到TypeScript playground中,您会看到。错误是:
Argument of type '"alpha"' is not assignable to parameter of type 'this[keyof this] extends string ? keyof this : never'.
为什么这个特定的调用会失败?我猜这与 TypeScript 如何推断 的类型有关this
,但细节对我来说是模糊的。
解决方案
我同意 arthem 最可能的罪魁祸首是 polymorphic this
。虽然很明显的类型this
将是多态的this
。虽然您可以肯定地说C['alpha']
is of type string
,this['alpha']
但您不能这么说,您只能说this['alpha'] extends string
这是编译器要遵循的更复杂的关系。不确定这个类比是否有帮助,但多态this
就像类的隐藏类型参数一样,使用它也受到类似的限制。例如,由于泛型类型参数可以说的限制,内部g
的类型obj['prop']
不知道再次出现:string
function g<
T,
K extends keyof Pick<T, P<T, string>>
>(obj: T, prop: K): void { obj[prop].charAt(0) /*error*/}
虽然以上是推测(我承认有点模糊),但解决上述错误的解决方案将解决问题,this
即设置我们的约束,即只能string
以不同的方式传递键。
function g3<
K extends string | number | symbol,
T extends Record<K, string>
>(obj: T, prop: K): void { obj[prop].charAt(0) /* ok*/ }
class C {
public alpha!: string;
public beta!: number;
public f(): void {
g3(this, "alpha"); // also ok as expected
g3(this, "beta"); //not ok
}
}
推荐阅读
- postgresql - 带有消息的 Postgresql docker 容器 - MessageText:关系“用户”不存在
- python - 如何在pygame中禁用按键并按住?
- python - 在 Python 中的多处理中使用锁时出错
- amazon-web-services - AWS Control Tower 无法完全设置您的登录区:...因为日志组已存在
- c# - 为什么枚举不会触发默认选项?
- java - 自定义哈希表删除功能
- reactjs - 使用名称而不是 id 来响应路由
- javascript - Express.js 渲染未命名为 index 的 html 文件时出错
- javascript - 将类数据绑定到 XMLHttpRequest 类而不删除 xhr 数据
- r - 具有多个图层的形状单击事件