Replies: 1 comment 3 replies
-
I got a solution to verify only string literals: type IsStringLiteral<T> = T extends string
? string extends T
? false
: Uppercase<T> extends Uppercase<Lowercase<T>>
? Lowercase<T> extends Lowercase<Uppercase<T>> ? true : false
: false
: false
type A = Expect<Equal<true, IsStringLiteral<'foo'>>>
type B = Expect<Equal<true, IsStringLiteral<Uppercase<'foo'>>>>
type C = Expect<Equal<false, IsStringLiteral<Uppercase<`foo${string}`>>>>
type D = Expect<Equal<false, IsStringLiteral<`foo${string}`>>>
type E = Expect<Equal<false, IsStringLiteral<`foo${number}`>>>
type F = Expect<Equal<false, IsStringLiteral<string>>> Check out this playground @jly36963 do you think that will help making the first solution work? |
Beta Was this translation helpful? Give feedback.
3 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Supporting non-literal types
Problem
Differentiating between string and string literal
The utilities in string-ts were written with the literal use case in mind.
Passing non-literal types (eg:
string
) as arguments will likely return bad types.The
Length<string>
issue can be fixed by updating the type definition like so.We know type
T
isstring
ifT extends string
andstring extends T
.This update was made to many of the string-ts type utilities in this PR.
The problem is, there are other string types that are:
string
Examples: template strings and intrinsic string manipulation types.
This means our ability to gracefully handle non-literal types becomes more complex.
As of right now, we only handle
string
and literal, none of the in-between types.(More on this below.)
TS built-in casing utils
The Intrinsic String Manipulation Types in TypeScript are only meant to work with string literals, not
string
type.Source code for
Uppercase
:Uppercase
,Lowercase
,Capitalize
, andUncapitalize
are all defined similarly.The 'intrinsic' keyword is used to declare compiler-provided intrinsic types.
When using these utilities with
string
, it can't be reduced any further.There is value in
Uppercase<string>
not being reduced tostring
.It preserves a more narrow scope of possible values.(See below.)
Casing in string-ts
Context:
There are many casing-related type utilities in string-ts.
Most of the type utilities in the library are made from lower-level, piped utilities.
CamelCase
looks something like the following when you drill into the underlying utilities:Under the hood,
CamelCase
usesCapitalize
,Uncapitalize
, andLowercase
.As I said earlier, we currently handle
string
and literal types, not the ones between.Any piping of utilities -- whether internally (like the
CamelCase
example above) or externally (eg:Length<CamelCase<T>>
) -- are not handled properly unless the type falls neatly into the string or string literal bins.Potential Solutions
Use verbose types to determine non-literals
We could use a helper to better differentiate literals from non-literals.
Here is an example where I modify
Length
to better handle the other types.Note: this solution better handles intrinsic types, but additional changes would need to be made to support template string types.
Wrap the built-in TS string types to reduce complexity
In this PR, I made types that override the built-in casing utilities' behavior around intrinsic types, and it makes composite/piped types like
CamelCase
more straightforward.This approach keeps the casing-related types in string-ts much less verbose -- as they have less string type categories to consider -- but it is a fundamental deviation from TS behavior, and it loses type information.
Other
...
Beta Was this translation helpful? Give feedback.
All reactions