Repository navigation
Problem with infer two types from string at same time #56936
Description
Activity
The way template string inference works, consecutive placeholders can only have a head/tail relationship. You can’t do it in reverse -
infer Restwon’t consume more than one character, as doing so would require backtracking.Reacted by Andrea Simone Costa and Ryan CavanaughReacted by KirillThe way template string inference works, consecutive placeholders can only have a head/tail relationship. You can’t do it in reverse -
infer Restwon’t consume more than one character, as doing so would require backtracking.This would be closer to the truth if TS prohibited the use of anything other than "string" in the suffix. And since TS understands "SuffixType", then I expect that it will be able to inference it
${infer Rest}${SuffixType}Besides, this works as expected:
type Test<T extends string> = T extends `${infer A extends Digit}${infer B extends Digit}${infer C extends Digit}` ? [A, B, C] : never type t_1 = Test<'123'> // [1, 2, 3] type t_2 = Test<'1234'> // never
Reacted by Konstantin GrigorchukThis would be closer to the truth
It is the truth. It might not meet your needs, but that's intentionally how the algorithm works. Each placeholder only gets one chance to match, and the first match for each (going from left to right) is locked in. Whichever ones are left can only work with what remains of the string.
So when you do
Test_1<'101'>what happens is this:${infer Rest}is immediately followed by another placeholder, so always match at least one character.Rest = 1? Yes, it's unconstrained so that matches; take it and lock it in.${infer D extends Digit}D = 0? Yes, it matches andextends Digit, so lock it in.- End of string? Nope, and we can't backtrack to step 2 or 4 so overall match fails.
Besides, this works as expected
Yes, because
Digitis always one character, so the first match for the non-trailing elements always succeeds. You can't do a variable-sized match in the middle of a string unless it's anchored to a fixed character.if it work without
infer T extends, it have to work with it the same way
The root of the problem is that these two methods give different results in certain cases:T extends `${infer Rest}${Digit}`
T extends `${infer Rest}${infer D extends Digit}`
what happens is this
Yes, I saw the remark in documentation.
But this does not explain the difference in behavior
For example, I collected combinations of checking a string and inference a substring:
PlaygroundReacted by Kirill- addedQuestionAn issue which isn't directly actionable in codeAn issue which isn't directly actionable in code
on Jan 3, 2024 typescript-bot commented
on Jan 6, 2024 ContributorMore actionsThis issue has been marked as "Question" and has seen no recent activity. It has been automatically closed for house-keeping purposes.
Reacted by Ayrat, Kirill, Albert Muravtsev and Konstantin Grigorchukthe problem was not resolved
Reacted by KirillRyanCavanaugh commented
on Jan 8, 2024 MemberMore actionsAyrat (@AtataUruru) I don't see a demonstrated defect here, per #56936
Ayrat (@AtataUruru) I don't see a demonstrated defect here, per #56936
Did you look at the examples from #56936 (comment) ?
From the point of view of the algorithm described above, examples T_3 and T_4 should give the same result, but this is not the casetype T_3<T extends string> = T extends `${string}${infer D extends Digit}` ? true : false type T_4<T extends string> = T extends `${infer Rest}${infer D extends Digit}` ? true : false
Also in example T_5 it is expected that the result of “infer” will be a specific digit “D”, and not the entire set “Digit”
type T_5<T extends string> = T extends `${string}${infer D extends Digit}` ? D : never
RyanCavanaugh commented
on Jan 8, 2024 MemberMore actionsWe don't really have the spare resources to look at dozens of examples to figure out which you think are correct and which aren't. Please reduce this to something succinct and demonstrably wrong if you'd like it to be looked at more.
Reacted by Albert Muravtsev and Alexey Sokolov- addedNeeds InvestigationThis issue needs a team member to investigate its status.This issue needs a team member to investigate its status.and removedQuestionAn issue which isn't directly actionable in codeAn issue which isn't directly actionable in code
on Jan 8, 2024
🔎 Search Terms
If i want infer two types from string in same time with
infer U extends Subtype, I get different results depending on the input stringIt can be solved with two consecutive conditions, but it has its price ( in example you can see three different implementations with different result)
🕗 Version & Regression Information
⏯ Playground Link
https://www.typescriptlang.org/play?ts=5.4.0-dev.20240102#code/C4TwDgpgBAIglgczsKBeKAGKAfKBGHKAJkIGZCAWQgVkIDZCB2QgDkIE4AoTgeh6jgA7AGYQATlAA2AQwDOKACaJkUAGRQxEeVAD2wqPLFCEAwbsHQAxjsFLgcG51CQoAFS3AA+ngA8rqBAAHsAQtrJQAAYAJADeggCuALYARuIAvhEAfGhuAcGhCuHRMUKiEgBKHmmxpeKweSFhsMrAGZwAkAD8UADalfIANLAAuh0AXFAWAG51fFB+DQVFsQkp6ZkRUGBiOiGWIQpQ8eGpwjqa3HO1EpraegbARoIIQ8AAFqGmZVJyii0GEGstigQLsDkETnA0Hc8k8RAWQUahUiKySqTEGWy6H8iKWKJKIjq-VasXgSFaEQ63Rx+SaxWJ1QJ3xgiyaZOQbXaXV6xKGMFGXIm01m-GEcDE2lByHBWx2ewORxOEDOF3aQogMwkcwRtORxVW6LSG1lu0BCuOUFO5wgl341x+2iU5NeHzM9tuKHuhmMANBIJsYMczmhHk8pB1SOWcTR6SyORpkfx3uejPtLNxbJanOprL1NUJFSqpM53L6Hj5ArVkw1IqgYolKCl9hsJvlEEOFqtqvVmqg2oTeP1MYxxu2pv27cVluV1u4wagIVhCmkwGk3hyAHI8Bg8BvIS5F15l6u4Zvt3v54fPMe1+R0FuL1CF6Gb54qPeMI+Dy+V2vaPev2gK9bniSQvAIdAei3T8hjwUZL1DECwNPSCHyGDB4KfYCtFArw716DcN1gzDv1hJCvHfAiiMwEigMQnDkP-atNTnLDQzwCC3HYnwr1fPBsjmeILECSAJwUHtxH3OjYTwEhsW43jfzhAT+B0ABrCYoN3dDaOfGT8JhcCeJ-E9SBUo5hNEg4JLEKS9PAyjDO8YylyUihzKEoIrPbGzeB4AABYBZAAWi8s1QrEHZbIQmSmKc3xFJPahzPU1jSK8IhOKc+FErXfi+1UjSCPPYi7KvIg5K42EcpMtciBSoqtOojCytDIgDLalyjyUsyCt0RrCNKmKMsczrcrfBrNMGmi-MCkKwv2CKota6q4rG2rPGSvrUpWvCstDcNxvywTLLNHzipg5pyV0q9SEqpzDo2+rtoG7SZuGsMOthR7XNMjzTrEqbqPZYAboO0bvq6683P+hbrKovkWlGPg5tCkTwvEZaPtINbIfGra5h2uY7IAUXR-YIzxR54ggLFOCgBmoAACj8TImYASjQbIByafxugICYiE5jNCnpxnWY5rnchF8JqegfmoEFqBujlxW62kSRZBtUmAEd4g1nwAEEhgAISxKAxZZ1w2c51BudzcJDeV-A1aFh3LYl237ZlqATedgXiE5lWxBptXhA1rW0qsOQtByHoxbJqyfBJvWDavDjXno2RcO8TJMgGBPyeAZPU8kKHZMzsiGIyvOC4ZxOzRL-Wy-T0hK68ciw1rwuk5T5vy4odvPE79z857xu+7T9jqCHzvkrH+ui6bqfqrwWfq9zheoAbinJ5btqiHX7PkPqred+Lveofao+c7Ms+l8v8rB-s4eN9Huvt4f0ur5nl+5+7xevdv63TXn-De-F75AP7rdQ+YDj410gRPYBB025wNvgAz+UCV54WftheBE1EG72Qd9X+eCc7zwLqMIAA
💻 Code
🙁 Actual behavior
🙂 Expected behavior
Test_1, Test_2 & Test_3 has equal behaviour
Additional information about the issue
No response