Repository navigation
Closed
Labels
Domain: Literal TypesUnit types including string literal types, numeric literal types, Boolean literals, null, undefinedUnit types including string literal types, numeric literal types, Boolean literals, null, undefinedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScriptAn idea for TypeScript
Description
There are cases, where a property can not just be any string (or a set of strings), but needs to match a pattern.
let fontStyle: 'normal' | 'italic' = 'normal'; // already available in master
let fontColor: /^#([0-9a-f]{3}|[0-9a-f]{6})$/i = '#000'; // my suggestionIt's common practice in JavaScript to store color values in css notation, such as in the css style reflection of DOM nodes or various 3rd party libraries.
What do you think?
Reacted by Chris Watson, Stepan Mikhailiuk, guid-empty, Raphael Ferreira, Omar Rizwan, Tingan Ho, Alex Leung, Andrew Harper, AviFix, Andrey Rygin and 1885 more
Reacted by Dean Merchant, Carlos Engel Olivo, hash, Bruno Macabeus, Robert Molina, CHC, Igor Strebz, hinell and Nulled
Reacted by Takeshi Kano, karvulf, strusoftsawen, Aaron J, Jamie Haywood, Genkagaku.GPT, Bruno Macabeus, Carlos Alexandre, Assaf Noah Koren, Matteo Guarda and 28 more
Reacted by Johan Grahn, Erik Cupal, Lars Gleim, Christian, Daniel Kucal, Dawson Botsford, Ezzat Chamudi, Dmitry Luzanov, Dariusz Filipiak, S Panfilov and 162 more
Reacted by Maarten Nusteling, Jakub Kowalczyk, Erik Cupal, vfhrr, Lars Gleim, Christian, Melle Wynia, Fareez Ahamed, Kimmo Kiiski, Daniel Kucal and 291 more
Reacted by axelthat, Martin Jaskulla, Stefano Postal, James Vopni, Robert Mengual, Noal Balint, Mohamed Nabous, Daniel, Dominic C, Godwin Vinny Carole and 122 more
Reacted by Jordi Oliveras Rovira, Amit Beckenstein, Ben, Artur Grzesiak, Amr, Vitor Carvalho, Srikanth Deshpande, Eric Rushing, Nikita Domin, Pubudu Dodangoda and 63 more
Metadata
Metadata
Assignees
Labels
Domain: Literal TypesUnit types including string literal types, numeric literal types, Boolean literals, null, undefinedUnit types including string literal types, numeric literal types, Boolean literals, null, undefinedNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.SuggestionAn idea for TypeScriptAn idea for TypeScript
Activity
DanielRosenwasser commentedon Jan 24, 2016
Yeah, I've seen this combing through DefinitelyTyped, . Even we could use something like this with
ScriptElementKindin the services layer, where we'd ideally be able to describe these as a comma-separated list of specific strings.The main problems are:
"cat","dog", and"fish", then I need to write something like/dog|cat|fish(,(dog|cat|fish))*/."cat","dog", and"fish", how do I integrate them into this regex?zackarychapple commentedon Apr 13, 2016
Huge +1 on this, ZipCode, SSN, ONet, many other use cases for this.
radziksh commentedon May 11, 2016
I faced the same problem, and I see that it is not implemented yet, maybe this workaround will be helpful:
http://stackoverflow.com/questions/37144672/guid-uuid-type-in-typescript
rylphs commentedon May 18, 2016
As Mohamed Hegazy (@mhegazy) suggested I will put my sugggestion (#8665) here. What about allow simple validation functions in type declarations? Something like that:
The value that the type can accept would be determined by the function parameter type and by the function evaluation itself. That would solve #7982 also.
ozyman42 commentedon Jul 23, 2016
Raphael Ferreira (@rylphs) +1 this would make TypeScript extremely powerful
maiermic commentedon Aug 30, 2016
How does subtyping work with regex-validated string types?
where
RegExType_1andRegExType_2are regex-validated string types.Edit: It looks like this problem is solvable in polynomial time (see The Inclusion Problem for Regular Expressions).
basarat commentedon Oct 17, 2016
Would also help with TypeStyle : typestyle/typestyle#5 🌹
DanielRosenwasser commentedon Oct 17, 2016
In JSX, Ryan Cavanaugh (@RyanCavanaugh) and I've seen people add
aria-(and potentiallydata-) attributes. Someone actually added a string index signature in DefinitelyTyped as a catch-all. A new index signature for this would have be helpful.Igmat commentedon Nov 18, 2016
Design Proposal
There are a lot of cases when developers need more specified value then just a string, but can't enumerate them as union of simple string literals e.g. css colors, emails, phone numbers, ZipCode, swagger extensions etc. Even json schema specification which commonly used for describing schema of JSON object has pattern and patternProperties that in terms of TS type system could be called
regex-validated string typeandregex-validated string type of index.Goals
Provide developers with type system that is one step closer to JSON Schema, that commonly used by them and also prevent them from forgetting about string validation checks when needed.
Syntactic overview
Implementation of this feature consists of 4 parts:
Regex validated type
Regex-validated variable type
and the same, but more readable
Regex-validated variable type of index
and the same, but more readable
Type guard for variable type
and same
and using defined type for better readability
same as
Type gurard for index type
same as
and using defined type for better readability
same as
Semantic overview
Assignments
Unfortunately we can't check is one regex is subtype of another without hard performance impact due to this article. So it should be restricted. But there are next workarounds:
Unfortunately assigning of
stringvariable toregex-validatedvariable should also be restricted, because there is no guaranty in compile time that it will match regex.But we are able to use explicit cast or type guards as shown here. Second is recommended.
Luckily it's not a case for string literals, because while using them we ARE able to check that its value matches regex.
Type narrowing for indexes
For simple cases of
regex-validated typeof index see Type gurard for index type.But there could be more complicated cases:
Literals haven't such problem:
But for variables the best option is using type guards as in next more realistic examples:
But if we'll use better definition for
Gmailtype it would have another type narrowing:Unions and intersections
Actually common types and
regex-validatedtypes are really different, so we need rules how correclty handle their unions and intersections.Generics
There are no special cases for generics, so
regex-validatedtype could be used with generics in same way as usual types.For generics with constraints like below,
regex-validatedtype behaves like string:Emit overview
Unlike usual types,
regex-validatedhave some impact on emit:will compile to:
Compatibility overview
This feature has no issues with compatibility, because there only case that could break it and it is related to that
regex-validatedtype has emit impact unlike usual type, so this is valid TS code:when code below is not:
But second already WAS invalid, but due to another reason (type declaration was wrong).
So now we have to restrict declaring of variable with name same to type, in case when this type is
regex-validated.P.S.
Feel free to point on things that I probably have missed. If you like this proposal, I could try to create tests that covers it and add them as PR.
Added first tests for microsoft#6579
Minor improvments of tests for microsoft#6579
Test for intersections and unions from microsoft#6579
130 remaining items
brandonthomas commentedon Oct 1, 2020
This would solve the data- or aria- problem that most of us face in UX libraries if it can be applied to indexes.
brandonthomas commentedon Oct 1, 2020
Basically this but obviously that doesn't work because TS only allows string | number. Since this is essentially a string can it be enabled?
https://www.typescriptlang.org/play?target=99&ts=4.1.0-dev.20201001#code/LAKALgngDgpgBAEQIZicgzgCzgXjgAwBIBvAcgBMUkBaUgXxPTACcBLAOwHM78BuUDmBjMAZkgDG8AJIAVGEzjFQcFXADalVBkwAFZgHsoALmRakWALpGmbLvxB1QocfvYL0AV3GT06I3Fl5MFxFCipqISZSI1JIsHpeIA
chadlavi-casebook commentedon Oct 1, 2020
There was some reference to this limitation in the release notes. It creates a list of all the possible valid combinations, in this case it would create a union with 16,777,216 (i.e., 16^6) members.
thehappycheese commentedon Oct 6, 2020
This is a great idea... Igmat made some incredible posts back in 2016 that look good on paper anyway.
I found this because I wanted to make sure the keys of an object literal passed into my function were valid css class names. I can easily check at runtime... but to me it seems so obvious that typescript should be able to do this at compile time, especially in situations where I am just hard-coding object literals and typescript shouldn't have to figure out if MyUnionExtendedExotictype satisfies SomeArbitraryRegexType.
Maybe one day I will be knowledgeable enough to make a more productive contribution :/
rozzzly commentedon Oct 14, 2020
Wow. I honestly did not expect to see this get implemented, not anytime soon at least.
Chad Lavimoniere (@chadlavi-casebook)
I'd be curious to see how large that union could get before it became a problem performance wise. Steven (@styfle)'s example shows how easy it is to hit that ceiling. There's obviously going to be a some degree of diminishing returns of usefulness of complex types vs performance.
thehappycheese
I'm fairly confident in saying that it's not possible with the current implementation. If there was support for quantifiers and ranges you would probably get validation for BEM style class names. The standard js regex for that isn't too terrible:
^\.[a-z]([a-z0-9-]+)?(__([a-z0-9]+-?)+)?(--([a-z0-9]+-?)+){0,2}$You would also ditch the anchors because as the implementation stands, it's either an end-to-end match or nothing so
^and$are implied. Now that's a comparatively simple regex for a narrow subset of what is a valid css selector. For example:ಠ_ಠis a valid class name. I'm not kidding. CSS selectors are very permissive swhich makes them extremely difficult to validate. So your desire is probably out of scope for template literal types, at least for the foreseeable future. 😞AnyhowStep commentedon Oct 17, 2020
I'm sorry. I had to do this.
I implemented regular languages in TypeScript.
Playground #1, number of 1s is divisible by 3 but not by 2
Playground #2, hex string of length 6
More accurately, I implemented a simple deterministic finite automaton using TS 4.1
I mean, we can already implement Turing machines in TS. So, DFAs and PDAs are "easy", compared to that.
And template strings make this more usable.
The core types are actually simple and fit in < 30 LOC,
It's specifying the automatons that's the hard part.
But I'm pretty sure someone can make a regex to TypeScript DFA™ generator...
I'd also like to highlight that the "hex string of length 6" example shows you can make function parameters only accept strings matching the regex using ugly hackery,
Here's a bonus Playground; it implements the regex
/^hello .*/And another Playground; it implements the regex
/ world$/One final example, Playground; this is a floating point string regex!
Harpush commentedon Oct 17, 2020
AnyhowStep Well i used your DFA idea to implement a simple regex
[abc]{4}which means the letters abc in any order with missing but exactly the length of 4. (aaaa, abcc, bbcc, etc...).Playground
AnyhowStep commentedon Oct 17, 2020
https://cyberzhg.github.io/toolbox/min_dfa?regex=ZCgoYmQqYiopKmMpKg==
https://github.com/CyberZHG/toolbox
If I had more willpower, I'd grab something like the above and use it to turn regexes into TS DFAs™ lol
AnyhowStep commentedon Oct 17, 2020
Okay, I just threw together a prototype,
https://glitch.com/~sassy-valiant-heath
[Edit] https://glitch.com/~efficacious-valley-repair <-- This produces way better output for more complicated regexes
[Edit] It seems like Glitch will archive free projects that are inactive for too long. So, here's a git repo with the files,
https://github.com/AnyhowStep/efficacious-valley-repair/tree/main/app
Step 1, key in your regex here,

Step 2, click convert,

Step 3, click the generated TS playground URL,

Step 4, scroll down till

InLanguage_0,Step 5, play with input values,

Shoutout to Kevin P. Dyer (@kpdyer) , author of https://www.npmjs.com/package/regex2dfa , for doing the heavy lifting of the conversion
iTob191 commentedon Oct 18, 2020
In case someone needs something a little more powerful, here's a Turing machine 😆
Playground
RyanCavanaugh commentedon Oct 19, 2020
This thread has gotten too long to read and many of the comments are either addressed by template literal types or are off-topic. I've created a new issue #41160 for discussion of what remaining use cases might be enabled by this feature. Feel free to continue discussing type system parsers here 😀
Mutefish0 commentedon May 20, 2022
Here is a workaround :)
RegExpRegExp commentedon Apr 24, 2023
const cssColor:
#${$rp<$d | $a, 3, 3>}= ""; 👉 no Problemconst cssColor:
#${$rp<$d | $a, 3, 6>}= ""; 👉 [Expression produces a union type that is too complex to represent.(2590)"]const cssColor:
${$rp<$d, 4, 4>}= ""; 👉 no Problemconst cssColor:
${$rp<"1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9", 5, 5>}= ""; 👉 no Problemconst cssColor:
${$rp<$d , 5, 5>}= ""; 👉 [Expression produces a union type that is too complex to represent.(2590)"]maybe maxLength? less than 100000, large than 45000, so typescript must't regexping string
(我搁这论猜想呢,咱就说,刚好让你不能搞好css 的颜色六位联合类型,超过最大值了家人们谁能懂 :))
Kavian77 commentedon Apr 22, 2024
For those who need type-safety on "predefined" attributes, here is what helped me:
To extend
React.HTMLAttributes:In case you need to type every
data-*, you can do: