我有一个精心设计的例子,它是从我正在进行的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
这里,bar
是foo
的有效参数,尽管bar
的第一个参数的字段比foo
所说的字段多。这意味着,在这里提供bar
作为回调的人会认为他们的论点中会有c
string
,但他们不会。
这并不是说没有对参数进行类型检查。以下正确失败:
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
请注意,foo
的a
参数被键入为T&{}
,而不仅仅是T
。这样做是为了降低该推理位点的先验性。由于T
可以从fn
或a
推断,我们希望确保编译器支持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_。因此,您应该能够在需要A
或B
的任何位置使用C
的实例。如果你不能,那就太奇怪了。
如果你申请的工作需要计算机科学学位,那么即使你有额外的学位,你也有资格。如果他们除了拥有额外的技能之外没有其他原因拒绝你,你会感到不安。