为什么打字稿不允许在字符串中调用concat string []类型?

时间:2018-06-14 06:33:52

标签: javascript typescript type-systems duck-typing

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);

上面的代码。我可以concatstring类型拨打string[]。那么为什么TypeScript不允许在concat类型中调用string | string[]

错误是:

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.

因为他们有不同的退货类型?但我认为TS可以推断error的类型是S。这是故意设计吗?如果是,为什么?

1 个答案:

答案 0 :(得分:4)

因为虽然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);