Open Akindin opened 2 weeks ago
I don't really understand the value, to be honest
Case 1: The input to concat
is a string
. In this situation, nothing changes
Case 2: The input to concat
is a single literal. In this situation, why not just use a template literal?
Case 3: The input to concat
is a union. In this situation, a combinatorial explosion is very likely, which is bad.
In case of general string type my proposal doesn't aim to change this, it focuses on preserving literal types when possible. This is about enhancing the handling of literal strings, not general strings.
Also with concat you can do feats like this with type inference
const fields = ["name", "id", "cost"] as const;
const test3 = "123".concat(...fields);
As for now template literals can't infer the string literal type unless explicitly specified.
function generateURL<T extends string>(value: T) {
return "https://api.example.com/".concat(value);
}
function generateURLTemplate<T extends string>(value: T) {
return `https://api.example.com/${value}`;
}
const userURL = generateURL('user'); // infers the type
const userURL2 = generateURLTemplate('user'); // becomes just string
About combinatorial explosion this issue does exist with template literals and there is an interesting proposal Lazy evaluation of template literals. For autocomplete purposes it can show the next possible literal in a sequence, instead of trying to generate all the variants. With lazy evaluation it is possible to check robust config in compile time, for something like date format validation or language restrictions to reduce the probability of out of ASCII rande identical symbols to pass (highlighting helps, but not with mixed text where you can have one fields that can have everything and another only ASCII symbols).
š Search Terms
string generic methods, string concat, checked domain literal types
Related issues #44268
ā Viability Checklist
ā Suggestion
Current Behavior: Currently, any manipulation on string other then assigning to literals and using
${templates}
doesn't infer the type from literal string. Basic toString and valueOf will lose type of literal string in the process. Desired Behavior: I propose enhancing the type definitions for String interface so that it can infer the exact type when used with string literals and templates. This would improve type safety and developer experience when working with string manipulation. At least valueOf, toString, toUpperCase, toLowerCase can be implemented without changing something other than the definition of String interface.Example of Current Issue:
Proposed Solution:
Introduce a new type definition for
concat
that uses variadic tuple types to infer the correct concatenated string literal type:Benefits:
Potential Drawbacks:
interface String { concat<This extends string, S extends string[]>(this: This, ...strings: S):(this: This): This;
toUpperCase(this: This): Uppercase;
toLowerCase(this: This): Lowercase;
valueOf(this: This): This;
}
${This}${Join<S, ''>}
; toStringlet a = "123".concat("qwerty");
a = "something else"; // this will result in error if implemented as interface modification because of inferred type "123qwerty"
Here, despite knowing that basePath is "/api" and usersPath is "/users", TypeScript loses the literal type information after concatenation, inferring fullPath as string, rather than "/api/users". This loss of precision means we can't rely on TypeScript to enforce strict types when building paths or identifiers, leading to potential runtime errors.
š» Use Cases