Is it possible to make type-annotation like this?
name: OnlyAlfabetChars
where
name = "someAlfabetChars"
is allowed but
name = "some alpfabet"
or
name = "123"
is not allowed.
There is no specific type in TypeScript that acts this way. There is an open feature request at microsoft/TypeScript#41160 for regular-expression validated string types that would probably give you this, but for now this is not implemented.
The closest you can get to this is to write a generic type that acts as a constraint on a string literal type, so that T extends OnlyAlphabet<T> if and only if T is a string literal type composed only of alphabetic characters. And that means you would need a generic helper function to infer the generic type argument, so instead of const x: OnlyAphabet = "abcdef"; you'd have to write const x = onlyAlphabet("abcdef").
So, how can we implement OnlyAlphabet<T>? We need to use template literal types to inspect the characters that make up a string, and in order to iterate over these characters we have to write it as a recursive conditional type. Here's one approach:
type OnlyAlphabet<T extends string, A extends string = ""> =
T extends `${infer F}${infer R}` ?
OnlyAlphabet<R, `${A}${Uppercase<F> extends Lowercase<F> ? "A" : F}`> :
A;
const onlyAlphabet = <T extends string>(
x: T extends OnlyAlphabet<T> ? T : OnlyAlphabet<T>
) => x;
So OnlyAphabet is a tail-recursive conditional type which checks each character in the input string. If it's an alphabetical character it leaves it alone; otherwise it replaces it with a capital A. So OnlyAlphabet<"abcdef"> is just "abcdef", but OnlyAlphabet<"abcd3f"> is "abcdAf".
Note that I take the shortcut that a character is alphabetical if and only if Uppercase<F> extends Lowercase<F> is false, using the intrinsic Uppercase<T> utility type and the Lowercase<T> utility type. This isn't perfect, but it works for a lot of character sets for which every alphabetical character has a distinct upper and lower case version, while non-alphabetical characters do not. If you have some other idea of what makes a character "alphabetical" and it can be implemented in TypeScript's type system, feel free to change it.
The onlyAlphabet helper function is generic in T that's constrained to string. I would love to write <T extends OnlyAlphabet<T>>(x: T)=>x, but that's an illegally circular constraint. Instead I use a quirk of inference and write <T extends string>(x: T extends OnlyAlphabet<T> ? T : OnlyAlphabet<T>)=>x. When you call it, the compiler will infer T to be the type of the x input, and then it will check T extends OnlyAlphabet<T>. If it succeeds, then the call succeeds because it amounts to <T extends string>(x: T)=>x which will work. If it fails, then the call fails, because it amounts to <T extends string>(x: OnlyAlphabet<T>) => x which will not match.
Let's test it out:
let x = onlyAlphabet("someAlphabetChars"); // okay
let y = onlyAlphabet("some alphabet"); // error!
// Argument of type '"some alphabet"' is not assignable to parameter of type '"someAalphabet"'
let z = onlyAlphabet("123"); // error!
// Argument of type '"123"' is not assignable to parameter of type '"AAA"'
Looks good. The compiler accepts a purely alphabetic string, but rejects ones with non-alphabetic characters and complains that the non-alpha character is not the letter A (so "some alphabet" is not "someAalphabet" and thus rejected).
In case it matters, this also works for other character sets that have distinct upper/lower case:
let w = onlyAlphabet("κάποιοαλφάβητο"); // okay
let v = onlyAlphabet("какойтоалфавит"); // okay
But fails for character sets with no such distinction:
let u = onlyAlphabet("いくつかのアルファベット"); // error!
// Argument of type '"いくつかのアルファベット"' is not assignable to parameter of type '"AAAAAAAAAAAA"'
So be careful.
TypeScript const valid: OnlyLetters = "someAlphabetChars"; const invalid: OnlyLetters = "some AlphabetChars"; ?
"κάποιοαλφάβητο"be accepted? Should"какойтоалфавит"be accepted? Should"いくつかのアルファベット"be accepted? The first two are easy because those character sets make a distinction between uppercase and lowercase; the last one is hard. I can write up my answer but I hope you'll answer my question first