microsoft / microsoft/TypeScript

Problem with infer two types from string at same time

Open
#56,936 11 comments 2 reactions 1 assignee View on GitHub

@rbuckton is already working on this.

Since Jan 8, 2024.

Needs Investigation
Dominant language
Go
Stars
111k
Forks
14.4k
Avg merge
1d 19h
Merged PRs (30d)
117

Description

🔎 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 string

type Test<T extends string> =  T extends `${infer Rest}${infer D extends Digit}`
  ? `${Rest}[${D}]`
  : T

It 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
  • This code does not work in versions earlier than 4.7
  • This changed between versions 4.7 and 4.8
  • The result given in the comments to the code corresponds to versions 4.8-5.3
⏯ 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
type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

// infer last digit & rest of string in one condition
type Test_1<T extends `${number}`> = T extends `${infer Rest}${infer D extends Digit}`
	? [Rest, D]
	: never // <T extends `${number}>` protected us before

// infer rest of string, then infer last digit second condition
type Test_2<T extends `${number}`> = T extends `${infer Rest}${Digit}`
	? T extends `${Rest}${infer D extends Digit}`
		? [Rest, D]
		: never
	: never // <T extends `${number}>` protected us before

// infer last digit, then infer rest of string second condition
type Test_3<T extends `${number}`> = T extends `${string}${infer D extends Digit}`
	? T extends `${infer Rest}${D}`
		? [Rest, D]
		: never
	: never // <T extends `${number}>` protected us before
🙁 Actual behavior
type test_11 = Test_1<'101'> // unexpected: never
type test_12 = Test_1<'10'> // ok: ['1', 0]
type test_13 = Test_1<'1'> // unexpected: never
type test_14 = Test_1<'0'> // unexpected: never
//@ts-expect-error
type test_15 = Test_1<''> // ok

type test_21 = Test_2<'101'> // ok: ['10', 1]
type test_22 = Test_2<'10'> // ok: ['1', 0]
type test_23 = Test_2<'1'> // ok: ['', 1]
type test_24 = Test_2<'0'> // ok: ['', 0]
//@ts-expect-error
type test_25 = Test_2<''> // ok

type test_31 = Test_3<'101'> // unexpected: ['10', Digit]
type test_32 = Test_3<'10'> // ok: ['1', 0]
type test_33 = Test_3<'1'> // unexpected: ['', Digit]
type test_34 = Test_3<'0'> // unexpected: ['', Digit]
//@ts-expect-error
type test_35 = Test_3<''> // ok
🙂 Expected behavior

Test_1, Test_2 & Test_3 has equal behaviour

Additional information about the issue

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.