TypeScript Version: 4.1.0-beta
Search Terms:
Code
type Join<T extends string[], D extends string> =
T extends [] ? '' :
T extends [string] ? `${T[0]}` :
T extends [string, ...infer U] ? `${T[0]}${D}${Join<U, D>}` :
string;
Expected behavior: string[] should be inferred
Actual behavior: unknown[] is inferred
Playground Link: https://www.typescriptlang.org/play?ts=4.1.0-beta#code/C4TwDgpgBAUg9gSwHYB4AqUIA9gSQEwGcpDgAnZAcygG0BdAGigBFMc8iTyqA+KAXgBQUEVAzZcBYvSgB+KAHIFUAFzDR49lNqkKSSnTlQABgBIA3mhoAGOgF9jq9SM2TONXVSYA6X8gBmEGRQAKqG8maWNvYWzHYW8MgoIUzMPA5Oolx6lADcQA
Related Issues:
While it would be nice if TypeScript support this case, be aware that there is a workaround (for this and all related problems): you can replace U with U extends string[] ? U : never, which effectively acts as a "truth me, or explode later if I'm wrong":
type Join<T extends string [], D extends string> =
T extends [] ? '' :
T extends [string] ? `${T[0]}` :
T extends [string, ...infer U] ? `${T[0]}${D}${Join<U extends string[] ? U : never, D>}` :
string;
The conditional will never fail (provided that there's no bug in the TypeScript compiler and your reasoning that it is definitely string[] is remains actually correct).
You can also consider something like U extends string[] ? U : ["uh oh, something went wrong - check assumption on line 4"] so that the literal type _might_ show up and allow you to debug later. That's a handy debugging technique, anyway.
As a workaround I used the following expression inside Join
U & string[]
I don't think there's a good path forward that could accomplish this. We'd have to have a lot of extra higher-order reasoning to determine that ...infer U would always produce something assignable to string[]
Most helpful comment
While it would be nice if TypeScript support this case, be aware that there is a workaround (for this and all related problems): you can replace
UwithU extends string[] ? U : never, which effectively acts as a "truth me, or explode later if I'm wrong":The conditional will never fail (provided that there's no bug in the TypeScript compiler and your reasoning that it is definitely
string[]is remains actually correct).You can also consider something like
U extends string[] ? U : ["uh oh, something went wrong - check assumption on line 4"]so that the literal type _might_ show up and allow you to debug later. That's a handy debugging technique, anyway.