在 Typescript 中传递回调 - 为什么回调的参数不能匹配和编译?



我有一个精心设计的例子,它是从我正在进行的React回调中派生出来的。

interface A {
a: string
b: string
}
interface B {
a: string
b: string
c: string
}
function foo(fn: (a: A) => void, a: A) {
fn(a)
}
function bar(arg: B): void {
console.log(arg.c)
}
foo(bar, {a: 'a', b: 'b'}) // This works, unfortunately

这里,barfoo的有效参数,尽管bar的第一个参数的字段比foo所说的字段多。这意味着,在这里提供bar作为回调的人会认为他们的论点中会有cstring,但他们不会。

这并不是说没有对参数进行类型检查。以下正确失败:

function baz(arg: string) { }
foo(baz, {a: 'a', b: 'b'}) // This fails correctly

这里到底发生了什么?有没有一种方法可以指定类型,使行为更接近理想?

这似乎是泛型的一个很好的用例。您需要确保作为参数传入的类型与函数参数兼容。如果这些是相同的泛型参数,编译器应该检查它们是否一致。

interface A {
a: string
b: string
}
interface B {
a: string
b: string
c: string
}
function foo<T extends A>(fn: (a: T) => void, a: T & {}) {
fn(a)
}
function bar(arg: B): void {
console.log(arg.c)
}
foo(bar, {a: 'a', b: 'b'}) //error

请注意,fooa参数被键入为T&{},而不仅仅是T。这样做是为了降低该推理位点的先验性。由于T可以从fna推断,我们希望确保编译器支持fn,即使它可以为T选择一个使两个参数兼容的类型(在这种情况下,该类型将是A(。我不记得我在哪里发现了这种行为,但我相信编译器团队的一名成员说,在可预见的未来,它是可以依赖的:-(

我觉得这很有趣,我想这可以解释为什么它能工作,不幸的是,它不能阻止类似的情况…:(

https://www.typescriptlang.org/docs/handbook/type-compatibility.html

接口是一个契约,它需要一个结构来提供某些属性(或行为(。对于任何支持接口概念的语言来说都是如此。

看看这个例子:

class C implements A, B {
a: string
b: string
c: string    
}

类型CCD_ 18符合CCD_ 19和CCD_。因此,您应该能够在需要AB的任何位置使用C的实例。如果你不能,那就太奇怪了。

如果你申请的工作需要计算机科学学位,那么即使你有额外的学位,你也有资格。如果他们除了拥有额外的技能之外没有其他原因拒绝你,你会感到不安。

最新更新