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

nit*_*ter 13 typescript

有这样的例子:

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>
Run Code Online (Sandbox Code Playgroud)

沙箱

当我尝试扩展BTypeScript 时写入:

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

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

更新#1:

我无法解释这一点,但似乎如果我用类替换接口,则键入效果会很完美。

更新#2:

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

更新#3

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

interface A {
    method: (itself: this) => string;
}
Run Code Online (Sandbox Code Playgroud)

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

interface A {
    method(itself: this): string;
}
Run Code Online (Sandbox Code Playgroud)

它根本没有任何意义。但在寻找这种行为的原因时,我发现了这个很好的答案。它让我了解了这种差异的原因。

有人提到了 TypeScript 选项strictFunctionTypes

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

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

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

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

更新#4

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

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

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

更新#5

我找到了另一个解决方法

type Method<T extends (...args: any) => any> = {
    f(...args: Parameters<T>): ReturnType<T>;
}['f'];
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)

你自己检查一下。这比禁用 更好strictFunctionTypes,但它仍然是解决方法。

Bis*_*jha 2

关键字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>

Run Code Online (Sandbox Code Playgroud)

代码游乐场

解决方案2:

我们可以创建method<T> (): void一个泛型函数来解决context-relatedfor 的歧义。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
}

Run Code Online (Sandbox Code Playgroud)

代码游乐场解决方案 2