为什么 typescript 不允许在字符串中调用 concat |字符串 [] 类型?
why typescript disallow call concat in string | string[] type?
const s: string = 'foo';
const pass1 = (origin: string) => origin.concat(s);
const pass2 = (origin: string[]) => origin.concat(s);
type S = string | string[];
const error = (origin: S) => origin.concat(s);
上面的代码。我可以在 string
或 string[]
类型中调用 concat
。那么为什么 TypeScript 不允许在 string | string[]
类型中调用 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.
因为它们有不同的 return 类型?但是我认为TS可以推断出error
的类型是S
。是故意设计的吗?如果是,为什么?
因为虽然 concat
方法在两种类型之间是通用的,但两者之间的签名非常不同,因此 Typescript 无法真正合并方法的声明。虽然不理想,但您可以使用类型保护来区分这两种类型:
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);
const s: string = 'foo';
const pass1 = (origin: string) => origin.concat(s);
const pass2 = (origin: string[]) => origin.concat(s);
type S = string | string[];
const error = (origin: S) => origin.concat(s);
上面的代码。我可以在 string
或 string[]
类型中调用 concat
。那么为什么 TypeScript 不允许在 string | string[]
类型中调用 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.
因为它们有不同的 return 类型?但是我认为TS可以推断出error
的类型是S
。是故意设计的吗?如果是,为什么?
因为虽然 concat
方法在两种类型之间是通用的,但两者之间的签名非常不同,因此 Typescript 无法真正合并方法的声明。虽然不理想,但您可以使用类型保护来区分这两种类型:
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);