Typescript 我可以创建比字符串更具体的类型吗?
例如,我有一个用户类型:Typescript 我可以创建比字符串更具体的类型吗?,typescript,Typescript,例如,我有一个用户类型: type User = { name: string; city: string; email: Email; password: Password; } 我可以在电子邮件中使用string,但我有一些限制,这就是为什么我想在这里键入电子邮件。限制包括: 它一定是某种形状的。只允许使用字符a-z和两个特殊字符,和@。例如,戴夫。morrison@gmail.com这是有效的形状,戴夫-morrison@gmail.com无效 它的长度必须有限 比如
type User = {
name: string;
city: string;
email: Email;
password: Password;
}
我可以在电子邮件中使用string
,但我有一些限制,这就是为什么我想在这里键入电子邮件。限制包括:
和@。例如,戴夫。morrison@gmail.com这是有效的形状,戴夫-morrison@gmail.com无效
type Email = /pattern here/
是否可以创建此类型?唯一比字符串更具体的类型是特定字符串: 不幸的是,你只能这么做。如果输入不受几个硬编码值的限制,则特定的Typescript类型并不用于指定有关一般用户输入的内容,而不是其类型。出于类似的原因,你不能做类似的事情
type BigNum = number > 1000;
唯一比字符串更具体的类型是特定字符串: 不幸的是,你只能这么做。如果输入不受几个硬编码值的限制,则特定的Typescript类型并不用于指定有关一般用户输入的内容,而不是其类型。出于类似的原因,你不能做类似的事情
type BigNum = number > 1000;
正确的答案可能是像@lionelrowee那样使用品牌的一种类似于名义的类型;除非您正在处理这些电子邮件地址字符串,以便这些电子邮件地址字符串在代码中硬编码为字符串文本,否则编译器无法强制执行此类约束。编译器将只看到
字符串
即使编译器知道您指定的确切字符串文本,例如const str=”foo@bar.com“
,像这样验证字符串超出了TypeScript 4.0的能力
令人惊奇的是,它不会超出TypeScript 4.1的能力,它将引入模板文字类型(如中实现的)。。。它实际上可以对字符串文本执行操作 不幸的是,据我所知,它将处于TypeScript能力的边缘。为了让编译器验证字符串长度不超过(比如)32个字符,并且它必须只包含字母字符、
“
”和“@”
,您必须使用递归条件类型(也计划在中实现TS4.1)。在每一个转弯处,你都会发现自己在避免各种递归或组合限制;对于长度仅为10个字符左右的字符串,编写一些中断编译器的代码是很容易的。即使您设法不达到极限,编译器也会变得很慢。键入无效电子邮件并等待10秒钟,编译器才会显示错误。这是一个混乱,我不推荐它,至少在TS4.1中是这样
但我太喜欢这些东西了,不能不做:
type Lower = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
type AllowedChars = Lower | '.' | '@'
type RestrictedToChars<T extends string, A extends string, Y = T, N = never> =
string extends T ? N :
T extends `${infer F}${infer F}${infer F}${infer F}${infer F}${infer F}${infer R}` ?
[F] extends [A] ? RestrictedToChars<R, A, Y, N> : N :
T extends `${infer F}${infer F}${infer F}${infer R}` ?
[F] extends [A] ? RestrictedToChars<R, A, Y, N> : N :
T extends `${infer F}${infer R}` ?
[F] extends [A] ? RestrictedToChars<R, A, Y, N> : N :
Y
类型CheckMaxLength
采用字符串文字T
和最大数字长度L
,如果T
最多L
个字符,则计算为:Y
,如果T
超过L
个字符,则计算为N
然后,您可以将Email
定义为字符串文本类型T
上的通用验证器,并以相同的方式使User
通用:
type Email<T extends string> = T &
CheckMaxLength<T, 32, RestrictedToChars<
`${lowercase T}`, AllowedChars, T, ["Email can only contain alphabet or @ or ."]
>, ["Email needs to be 32 characters or less"]>;
type User<T extends string> = {
name: string;
email: Email<T>;
}
type Email=T&
CheckMaxLength,[“电子邮件需要不超过32个字符”]>;
类型用户={
名称:字符串;
电邮:电邮;
}
最后,您可以看到编译器执行验证:
const user = <T extends string>(user: User<T>) => user;
user({ name: "Dave Morrison", email: "Dave.Morrison@gmail.com" }); // okay
user({ name: "Van Morrison", email: "Van-Morrison@gmail.com" }); // error!
// ------------------------> ~~~~~
// '["Email can only contain alphabet or @ or ."]'
user({ name: "Jim Morrison", email: "Jim.Morrison.is.my.name.and.it.is.too.long@gmail.com" }); // error!
// ------------------------> ~~~~~
// '["Email needs to be 32 characters or less"]'
constuser=(user:user)=>user;
用户({姓名:“Dave Morrison”,电子邮件:“Dave。Morrison@gmail.com" }); // 可以
用户({姓名:“Van Morrison”,电子邮件:“Van-Morrison@gmail.com" }); // 错误!
// ------------------------> ~~~~~
//“[”电子邮件只能包含字母或@或。“”
用户({name:“Jim Morrison”,电子邮件:“Jim.Morrison.is.my.name.and.it.is.too。long@gmail.com" }); // 错误!
// ------------------------> ~~~~~
//“[“电子邮件必须少于32个字符”]
非常可怕!同样,我不建议你使用这个。但是当TS4.1发布时,从技术上讲,编译器可以通过这种方式验证字符串
正确的答案可能是使用@LionelRowee品牌的类似名义的类型;除非您正在处理这些电子邮件地址字符串,以便这些电子邮件地址字符串在代码中硬编码为字符串文本,否则编译器无法强制执行此类约束。编译器将只看到
字符串
即使编译器知道您指定的确切字符串文本,例如const str=”foo@bar.com“
,像这样验证字符串超出了TypeScript 4.0的能力
令人惊奇的是,它不会超出TypeScript 4.1的能力,它将引入模板文字类型(如中实现的)。。。它实际上可以对字符串文本执行操作 不幸的是,据我所知,它将处于TypeScript能力的边缘。为了让编译器验证字符串长度不超过(比如)32个字符,并且它必须只包含字母字符、
“
”和“@”
,您必须使用递归条件类型(也计划在中实现TS4.1)。在每一个转弯处,你都会发现自己在避免各种递归或组合限制;对于长度仅为10个字符左右的字符串,编写一些中断编译器的代码是很容易的。即使您设法不达到极限,编译器也会变得很慢。键入无效电子邮件并等待10秒钟,编译器才会显示错误。这是一个混乱,我不推荐它,至少在TS4.1中是这样
但我太喜欢这些东西了,不能不做:
type Lower = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';
type AllowedChars = Lower | '.' | '@'
type RestrictedToChars<T extends string, A extends string, Y = T, N = never> =
string extends T ? N :
T extends `${infer F}${infer F}${infer F}${infer F}${infer F}${infer F}${infer R}` ?
[F] extends [A] ? RestrictedToChars<R, A, Y, N> : N :
T extends `${infer F}${infer F}${infer F}${infer R}` ?
[F] extends [A] ? RestrictedToChars<R, A, Y, N> : N :
T extends `${infer F}${infer R}` ?
[F] extends [A] ? RestrictedToChars<R, A, Y, N> : N :
Y
类型CheckMaxLength
采用字符串文字T
和最大数字长度L
,如果T
最多L
个字符,则计算为:Y
,如果T
大于L
个字符,则计算为N
type Email = string & { readonly email: unique symbol }
type User = {
name: string
email: Email
}
// check with `is` return type
const isValidEmail = (maybeEmail: string): maybeEmail is Email => {
return maybeEmail.includes('@') && maybeEmail.length < 100
}
const aliceEmail = 'alice@email.com'
// OK - runtime type safety
if (isValidEmail(aliceEmail)) {
const alice: User = {
name: 'Alice',
email: aliceEmail,
}
}
// compiles with `as` (bypassing runtime safety)
const bob: User = {
name: 'Bob',
email: 'bob@email.com' as Email,
}
// compile-time error
const charlie: User = {
name: 'Charlie',
email: 'charlie@email.com',
}