此代码有效:
class A {}
class B {}
class C {}
const classCFromAOrB = (element: A | B): C => new C()
const a: A[] | B[] = [new A()]
const c: C[] = a.map(element => classCFromAOrB(element))
此代码不:
import { classA } from '../some'
import { classB } from './../some'
interface interfaceC {}
const render = (element: classA | classB): interfaceC => {
return {}
}
interface ResultsScreenProps {
resultsScreenPresented: boolean
answers: classA[] | classB[]
dismiss: SimpleFunc
}
const Screen: React.SFC<ResultsScreenProps> = (props) => {
const array: classA[] | classB[] = props.answers
const second: interfaceC[] = array.map(el => render(el)) // here is the error
...
}
在定义second
的行上出现错误:
[ts]无法调用类型缺少调用签名的表达式。 类型'(((callbackfn:(值:classA,索引:数字,数组:classA []) => ...'没有兼容的呼叫签名。
我在做什么错了?
如果classA看起来像这样,则该错误是可重现的:
class classA {
anyArg: number
constructor(anyArg: number) {
this.anyArg = anyArg
}
}
答案 0 :(得分:4)
正如我在评论中所述,you can't call methods which are union types。 (classA[] | classB[])['map']
的呼叫签名为
(
<U>(
callbackfn: (value: classA, index: number, array: classA[]) => U,
thisArg?: any
) => U[]
) | (
<U>(
callbackfn: (value: classB, index: number, array: classB[]) => U,
thisArg?: any
) => U[]
)
然后编译器放弃了。您可以做的是将类型从(classA[] | classB[])
扩展到(classA | classB)[]
。前者是“这是所有classA
元素的数组,或者是所有classB
元素的数组”,而后者是“这是元素的数组,每个元素都是一个classA
或classB
”。前者更具体,因为如果您知道arr[0]
是classA
,那么arr[1]
也将是classA
...而后者则较不具体,因为{ {1}}可以是arr[0]
,而classA
可以是arr[1]
。后者的优点是classB
具有单个签名:
(classA | classB)[]['map']
您可以调用它。
您的下一个问题,“如果我在任何类中定义任何内容,为什么它会停止工作”与structural typing有关。简而言之,TypeScript认为<U>(
callbackfn: (value: classA | classB, index: number, array: (classA | classB)[]) => U,
thisArg?: any
) => U[]
和classA
如果具有相同的成员,则它们是相同的类型。这可能令人惊讶,因为许多其他类型的语言都使用nominal typing,其中两个具有不同 names 的类型必然是不同的类型。但是TypeScript并不是真的那样工作。
如果classB
和classA
都没有属性,那么它们将被视为等同于classB
(空类型)。然后{}
减少为(classA[])|(classB[])
的{{1}}。那不是联合,所以您可以调用其({}[])|({}[])
方法。
如果您希望编译器将({}[])
与map
区别开,那么您应该give them different properties,至少直到(并且除非)TypeScript获得更多的一等标称值
希望对您有帮助。祝你好运。