Javascript 为什么typescript不允许在string | string[]类型中调用concat? 常量s:string='foo'; constpass1=(origin:string)=>origin.concat; constpass2=(origin:string[])=>origin.concat; 类型S=字符串|字符串[]; 常量错误=(原点:S)=>origin.concat;
上面的代码。我可以在Javascript 为什么typescript不允许在string | string[]类型中调用concat? 常量s:string='foo'; constpass1=(origin:string)=>origin.concat; constpass2=(origin:string[])=>origin.concat; 类型S=字符串|字符串[]; 常量错误=(原点:S)=>origin.concat;,javascript,typescript,type-systems,duck-typing,Javascript,Typescript,Type Systems,Duck Typing,上面的代码。我可以在string或string[]类型中调用concat。那么为什么TypeScript不允许在string | string[]type中调用concat 错误是: Cannot invoke an expression whose type lacks a call signature. Type '((...strings: string[]) => string) | { (...items: ConcatArray<string>[]): string
string
或string[]
类型中调用concat
。那么为什么TypeScript不允许在string | string[]
type中调用concat
错误是:
Cannot invoke an expression whose type lacks a call signature.
Type '((...strings: string[]) => string) | { (...items: ConcatArray<string>[]): string[]; (...items: (s...'
has no compatible call signatures.
无法调用其类型缺少调用签名的表达式。
键入“(…strings:string[])=>string){(…项:ConcatArray[]):string[];(…项:(s.)
没有兼容的呼叫签名。
因为它们有不同的返回类型?但我认为TS可以推断出
error
的类型是s
。这是故意设计的吗?如果是,为什么?因为虽然concat
方法在这两种类型之间很常见,但在这两种类型之间有非常不同的签名,所以Typescript不能真正合并m的声明方法。虽然不理想,但您可以使用类型保护来区分这两种类型:
const s: string = 'foo';
type S = string | string[];
const error = (origin: S) => typeof origin === 'string' ?
origin.concat(s) :
origin.concat(s);
或者直接断言为any
:
const s: string = 'foo';
type S = string | string[];
const error = (origin: S) => (origin as any).concat(s) as S
还可以选择将签名的并集转换为签名的交集。这在某些情况下可能很好,但在其他情况下则不行:
const s: string = 'foo';
type S = string | string[];
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
function mergeSignature<T, K extends keyof T> (value: T, method: K) : UnionToIntersection<T[K]>{
return ((...args: any[]) => (value[method] as any as Function).apply(value, args)) as any;
}
const error = (origin: S) => mergeSignature(origin, 'concat')(s);
常量s:string='foo';
类型S=字符串|字符串[];
类型UnionToIntersection=
(U扩展任何?(k:U)=>void:never)扩展((k:inferi)=>void)?I:never
函数mergeSignature(值:T,方法:K):UnionToIntersection{
返回((…args:any[])=>(值[方法]作为任意函数)。应用(值,args))作为任意函数;
}
常量错误=(原点:S)=>mergeSignature(原点“concat”)(S);
我更喜欢类型保护方式。谢谢。为什么在这种情况下TS不能合并结果类型?我可以编写一个函数,它可能返回
T1
或T2
,但我不需要将函数返回类型显式声明为T1 | T2
,TS可以推断出来。这里讨论了为什么他们不这样做,我想他们知道abo但毕竟,他们对这个问题发表了评论;)是的,在我在SOF中提出这个问题之前,我已经读过这个问题。我理解在联合类型中处理深度调用很困难,需要手工跟踪联合类型的组成,例如curry函数。但在我的情况下,这只是一个一级调用。这是一个设计权衡,但可以实现。对吗?@merito添加了一个新的解决方案,可以改变符号交叉点的签名联合使其可调用好消息是我们可以从TS 3.3中做到这一点。它还需要一些改进。例如,const-ret=error('msg')
,ret的类型是什么?ret
?TS推断它是s
,但它应该是string
。