接口中的 TypeScript this 应该引用它自己和子元素,而不仅仅是它自己

2024-01-05

有这样的例子:

interface A {
    method: (itself: this) => string;
}

interface B extends A {
    additionalProperty: boolean;
}

type Extend<T extends A> = A & { extension: number };

type ExtendedA = Extend<A>

type ExtendedB = Extend<B>

.

当我尝试延长B打字稿写道:

类型“B”不满足约束“A”。 属性“方法”的类型不兼容。 类型“(itself: B) => string”不可分配给类型“(itself: A) => string”。 参数“itself”和“itself”的类型不兼容。 类型“A”中缺少属性“additionalProperty”,但类型“B”中需要属性“additionalProperty”。(2344) input.tsx(6, 2): 此处声明了“additionalProperty”。

But B延伸A。它们应该是兼容的。

更新#1:

我无法解释这一点,但是看来如果我用类替换接口 https://www.typescriptlang.org/play?ts=4.6.2#code/MYGwhgzhAECC0G8BQBIAtgUwC4AsD2AJgBQCWWEGIAZgFzS4kQCUiqKATtgK7sB20AciwYIWAQG5UAXyQzQkGACFoGAB7DeBGPGQowBAmRJ5eYEAAV2eAA4Z2WAJ7QAvPXZcMkmUke3oAUXUMTQAeABUVIM1tAD4XaAiAMkRIjQhjXjpeLjQAIztoKUkfBz9AjQIMAnhXcuCCENgYpBKyqMqCZVr2kMUYoA打字效果完美。

更新#2:

嗯,它只适用于类方法,但不适用于例如箭头函数。还是很奇怪。

更新#3

如果接口按以下方式定义,则它将不起作用:

interface A {
    method: (itself: this) => string;
}

但如果它按以下方式定义,它就可以工作:

interface A {
    method(itself: this): string;
}

它根本没有任何意义。但寻找这种行为的原因我发现这个优秀的答案 https://stackoverflow.com/a/70277549。它让我了解了这种差异的原因。

有人提到了 TypeScript 选项strictFunctionTypes https://github.com/microsoft/TypeScript-Website/blob/v2/packages//tsconfig-reference/copy/en/options/strictFunctionTypes.md.

启用后,此标志会导致更正确地检查函数参数。

在开发此功能的过程中,我们发现了大量本质上不安全的类层次结构,包括 DOM 中的一些。因此,该设置仅适用于以函数语法编写的函数,不适用于以方法语法编写的函数

它解释了这种奇怪的行为差异的原因。我可以关闭这个选项,但这感觉像是一个解决方法。

我还需要另一个解决方案。

更新#4

我认为此错误是为了防止此类不安全的分配而指定的:

const a: A = {
    method(b: B) {
        return `${b.toString()} / ${b.additionalProperty}`;
    }
}

但此类错误并不特定于我的情况。

更新#5

我找到了另一个解决方法

type Method<T extends (...args: any) => any> = {
    f(...args: Parameters<T>): ReturnType<T>;
}['f'];
interface A {
    method: Method<(itself: this) => string>;
}

interface B extends A {
    additionalProperty: boolean;
}

type Extend<T extends A> = T & { extension: number };

type ExtendedA = Extend<A>

type ExtendedB = Extend<B>

自己检查一下 https://www.typescriptlang.org/play?ts=4.6.2#code/C4TwDgpgBAshwAsD2ATAPAFShAHsCAdigM5QAUAdFQIYBOA5sQFxTUEgCUUAvAHyvt+3KAG8AUAEgAZpRoNmUAAp1qAW3gRaxTLw4sASvACutAhnAQdAbjEBfANoByKY4C6NsQEsC+WlOoAxtAAgqKS6oioLHCR6GSewMQQADZSLIiexFx8UMTAtN70vDa2Yl4+mv5BUABC2HiEJFCh4hLUKCgJnkgE1MmKtEiQtKAsAEZISMkQbCVloJBQAKINRJj1+ESkwUJQWABkohuExN0ELARGqmOaULYeC9ArmygQKKHCz41oO-MWy6tXig6p9AWgarwgA。这比禁用更好strictFunctionTypes,但这仍然是解决方法。


The this关键字取决于定义它的上下文。 当它被定义在interface A它引用了A,并在interface B它引用了B

因此,在检查时它们都变得不兼容extends约束。

解决方案1:

因此,我们可以单独显式定义它们,也可以只添加它们的并集A | B

interface A {
    method: (itself: A | B) => string;
}

interface B extends A {
    additionalProperty: boolean;
}

type Extend<T extends A> = T & { extension: number };

type ExtendedA = Extend<A>

type ExtendedB = Extend<B>

代码游乐场 https://www.typescriptlang.org/play?ts=4.6.2#code/JYOwLgpgTgZghgYwgAgILIN4CgCQBbCMACwHsATALmQApgwBnCAGxivQB9kAhASmQF4AfMnpgooAOYBuLAF8sWUJFiIUXZBAAekEGXppMuOGTJ1gJEHCYAFKCQAO0MAE8qAIxIkmEOCBnysF0dkAFFtCF0AHgAVDXDdfVRhfmRYgDJMOJ16cxAqEABXPDdoZFkZQOdgsJ0yCDJ0FJqIskikhSCUZt169Sb41q5BLCA

解决方案2:

我们可以做method<T> (): void一个通用函数,以便context-related含糊不清this已解决。

interface A {
    method: <T> (itself: T) => void;
}

interface B extends A {
    additionalProperty: boolean;
}

type Extend<T extends A> = T & { extension: number };

type ExtendedA = Extend<A>

type ExtendedB = Extend<B>

const b: B = {
    method<B>() {
        console.log(this.additionalProperty) 
    },
    additionalProperty: true
}

代码游乐场解决方案 2 https://tsplay.dev/N7O94N

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

接口中的 TypeScript this 应该引用它自己和子元素,而不仅仅是它自己 的相关文章

随机推荐