TypeScript - 是否可以根据模式匹配甚至长度来验证字符串类型?

2024-04-04

考虑以下组件,它使用一个名为的库styled-components创建一个预样式Text成分:

const StyledText = styled(Text)`
  font-family: Roboto;
  color: ${(props: ITextProps) => props.color || '#000' }; 
`

where ITextProps is:

interface ITextProps {
  color: string;
}

有没有办法强制只将有效的十六进制字符串传递给我的组件?

理想情况下,颜色道具应始终与图案相匹配/#\d{3}(\d{3})?/g、# 后跟至少 3 位数字,并且可以选择再跟 3 位数字。如果这是不可能的,那么有没有办法至少强制字符串的长度为 4 或 7 个字符?

我的研究让我陷入了死胡同,所以我想知道是否有人知道我如何在 TypeScript 中实现这种行为。


2021-06-13:更新为 TS4.1+


不是真正在编译时,不是。有一个建议(现在位于 microsoft/TypeScript#41160) https://github.com/microsoft/TypeScript/issues/41160允许正则表达式验证字符串类型,但尚不清楚它是否会被实现。如果您想接受该建议并给它一个????并描述一个尚未列出的令人信服的用例,这不会有什么坏处(但它可能也不会真正有帮助)。

你可以try to use 模板文字类型 https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#template-literal-types为此以编程方式生成一个大的union https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types它匹配每个可接受的字符串文字。如果您只需要三位左右的数字,这甚至可以工作:

type UCaseHexDigit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | 
  '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
type HexDigit = UCaseHexDigit | Lowercase<UCaseHexDigit>
type ValidThreeDigitColorString = `#${HexDigit}${HexDigit}${HexDigit}`;
// type ValidThreeDigitColorString = "#000" | "#001" | "#002" | "#003" | "#004" | "#005" 
// | "#006" |  "#007" | "#008" | "#009" | "#00A" | "#00B" | "#00C" | "#00D" | "#00E" 
// | "#00F" | "#00a" | "#00b" | "#00c" | "#00d" |  // "#00e" 
// | ... 10626 more ... | "#fff"

但由于此类模板文字类型只能处理数万个成员的联合,因此如果您尝试使用六位数字来执行此操作,则会中断:

type ValidSixDigitColorString =
    `#${HexDigit}${HexDigit}${HexDigit}${HexDigit}${HexDigit}${HexDigit}`; // error!
//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Expression produces a union type that is too complex to represent

所以你必须使用解决方法。


一种解决方法是使用模板文字类型作为generic https://www.typescriptlang.org/docs/handbook/2/generics.html 约束而不是做ValidColorString具体类型。相反,有一个类似的类型AsValidColorString<T>需要一个字符串类型T and checks看看它是否有效。如果是的话,就不管它了。如果不是,则返回一个与错误颜色“接近”的有效颜色字符串。例如:

type ToHexDigit<T extends string> = T extends HexDigit ? T : 0;
type AsValidColorString<T extends string> =
    T extends `#${infer D1}${infer D2}${infer D3}${infer D4}${infer D5}${infer D6}` ?
    `#${ToHexDigit<D1>}${ToHexDigit<D2>}${ToHexDigit<D3>}${ToHexDigit<D4>}${ToHexDigit<D5>}${ToHexDigit<D6>}` :
    T extends `#${infer D1}${infer D2}${infer D3}` ?
    `#${ToHexDigit<D1>}${ToHexDigit<D2>}${ToHexDigit<D3>}` :
    '#000'

const asTextProps = <T extends string>(
   textProps: { color: T extends AsValidColorString<T> ? T : AsValidColorString<T> }
) => textProps;

这相当复杂;主要是将字符串分开T并检查每个字符,将坏的字符转换为0。然后,不要将某些内容注释为TextProps,你打电话给asTextProps对其进行验证:

const textProps = asTextProps({
    color: "#abc" // okay
})

const badTextProps = asTextProps({
    color: "#00PS1E" // error
//  ~~~~~
//  Type '"#00PS1E"' is not assignable to type '"#00001E"'.(2322)
})

这在编译时有效,但可能会带来更多麻烦。


最后,您可以退回到 TS4.1 之前的解决方案并创建一个名义上的子类型string with a 用户定义的类型保护 https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards缩小string值...然后跳过各种障碍来使用它:

    type ValidColorString = string & { __validColorString: true };

    function isValidColorString(x: string): x is ValidColorString {
      const re = /#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?/g; // you want hex, right?
      return re.test(x);
    }

Usage:

    const textProps: ITextProps = {
      color: "#abc"
    }; // error, compiler doesn't know that "#abc" is a ValidColorString
    
    const color = "#abc";
    if (isValidColorString(color)) {
      const textProps2: ITextProps = {
        color: color
      }; // okay now
    } else {
      throw new Error("The world has ended");
    }

后者并不完美,但它至少让您更接近执行此类限制。

希望能给你一些想法;祝你好运!

Playground 代码链接 https://www.typescriptlang.org/play?useDefineForClassFields=true#code/HYQwtgpgzgDiDGEAEAVCYYBsQBcIBkBLPAJxEwDERDMkBvAKCWaRwE8ZkBVAYRCggAJCAA8AIoQDmxJAF4kAcgAMCpAB9FARlUaFAJh2KAzIYUAWUwFZTANlMB2UwA5TATlMBBUwCFTPU2KmAKKmFApMLOycSMLiUjLyvPxCohLSOOpI+AD2AO4QJPDJADxJArFpxAB8EcxRyABq5IQAJigAFiQQEJU4PNmY2SQAyjgkhMCSckgABgDEACR0FfE4AL5LK+kby6mrazMA3LVIAPSnrByNzW2d3b39gyNjE1PyAERzSt-vmZ-fml+Gn+Sj0QKQIKM4JBZmhXyUljh3xs4JO5wh8PsSKUTmxrmxHmx3mxPGxYmxQWxFGxIGxACNUSwzhcQfBsS1wcyMd8IOCAHQCpCaJQ2PQ2JBgIbIAV8v5zABmiveDBO9SQTUwrWGhDi6UeQ1G40mchOTPmmz22wtuuIOy2tutvTtloduxt6yOXIKJCGAEI0RckAA-EOhsPhiORqPRmOx0MBpBBEQwLpQKCEbLAJAp7ItACuiCgSBASDzwAzWbVOHauCQhCLOGy2SQ8GyGEwolYza6KegEGAOAYaxVoEgsAQyDQ7dwBGIBXI-WAUDG1AH9FVVyQZRS7umylM2ky+lMJiPFiP1iPdiPjiPLiP7iPXiPviP-iPgSPISPYQ30XtGSJHw5QuhkGg5PkhQlNuAE1H+k7ZABxQoEgoh4MALRFsuRqSFU0woWh-aYTEoFIAA-KgSAAFxIEoxxMmqHhQBqrT6s8OHIahIjocR2GvHhsimiwBHcURRbmnQEzygUSBiJoOxSTJYh6ApwDSSQslGKp6myWY2lKZY+kaWINgHORQnMBJKCIaBxRyVUOzWUhykOUsTm2WIRiuXQ7nunZZjeb5vR2ZYgU2X5JkOTM1EWZRhEYeJiySWpSnyUsinGSp6UpcZWnRWRsVWeFwX2Y5xWrHZehhc5XlmVRsUKPCKgqkyrZLhk-BoNxAAKPowEW8icfFvEvJMVQABR4D1fVQDRdAtgMQw0SJPFFkxLEtGxhqvMheEUShNHrTcW2jZIu1IGsACUch4VNOC9dk-XHCcbXLqwaEPf10ydR9M3jYwTKtYtJA0Z8IB0myXLZAA1iAbAnFdLUsK9GR0iAbS-Y9A3FlAXX3X9AOA8wrZPKD8LdcMmiUl6JA+iQCbBmGDMoJuCgghTVPvKo9ZIMA2QdWmUigHSHZdpc0Rs01SicwofLjXoRh6Hol0IyrQ4qgwo7QHAiBIAAcm2EzkAAklA7Trgxm4bSdOHTHxxoAGT0EgAD6LsAG7HcD22TDRYx5sgazPUyEykPKE5IMbeOfUWhNEyTS3ql7Tw+5I9EsMOSPMPKZbwDgFZ1sxycGqd40iDR9uSJdNEiIXSeapt3unRbRMLe1SBdNMpxzAA2koAC0rggP38oeP3FAALp0Fp4194Pw+j+PU9aZdZGnGnXJsNkeZILkIBru0ogADQd1I7Q4AVrcdxAOB5iQWZdHyeDLmXl3p8wmdA+3d0xzRUeY19eQcdAYJxBhicGbIEaHBpnTE+rYMA0Bki0bI0BgAKAyNDPmuRWA1gyGDCGvweYlmtk3HCWc25vVAdMfBbJ351nlEgca9YSEp1LqAy611gFfzej-Gaeg-7RxmtMLhrdQE0VAbFIOUNYZsF5nkBGqFMACBbkTasPpsHAAgNgoItMhjjXeB0ZAuQhiYBaEgGsRYiIQA5G-BGKpM5AA

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TypeScript - 是否可以根据模式匹配甚至长度来验证字符串类型? 的相关文章

随机推荐

  • mb_convert_case 未定义函数(Symfony2 FOS/UserBundle)

    在我的 Symfony2 应用程序上 我收到错误 致命错误 在第 18 行 Applications MAMP htdocs application vendor bundles FOS UserBundle Util Canonicali
  • 对JPanel函数的关注:paintComponent()

    你好 我是java编程新手 我需要有人向我解释这些代码行 public class drawpanel extends JPanel public void paintComponent Graphics g super paintComp
  • zend 模型架构

    假设我的数据库中有两个表 项目和用户 我创建了两个扩展 Zend Db Table Abstract 的模型 Model DbTable Users and Model DbTable Projects 现在 创建一个实例是一个好的模式吗
  • 如何向 WordPress 添加简单的 jQuery 脚本?

    我阅读了 Codex 和一些关于在 WordPress 中使用 jQuery 的博客文章 这非常令人沮丧 我已经加载了 jQueryfunctions php文件 但所有的指南都很糟糕 因为他们假设你已经有大量的 WordPress 经验
  • 如何在 gradle 中获取当前选择的构建变体?

    我正在使用带有 gradle 2 2 的 Android Studio RC 我的构建变体部分中有一些变体 我可以选择我想要构建的变体 例如 为匈牙利或德国构建的一个 我在 gradle 脚本中启动了一些任务 例如根据风味 变体更改名称 但
  • Backbone.js 中的分页

    我知道有一个组件可以实现此目的 但根据我所看到的 您必须创建一个扩展组件的新集合 还有另一种方法可以在主干中进行分页吗 我所需要的只是一个上一个和下一个按钮 将每页的项目限制为 12 个 我一直在 javascript 上创建它 对于生产环
  • 尝试在 slack 上为 laravel-botman 启用事件订阅时,如何响应正确的质询值

    这不是我之前的问题的重复here https stackoverflow com questions 52850571 connecting slack to botman in laravel on localhost 我正在使用botm
  • 未找到图像或类型未知 Dompdf 0.8.1 和 CodeIgniter

    我想从生成的图像将图像加载到 PDF 我已经设置了isRemoteEnabled 为 true和 生成的 QRCode 工作正常 这是我的代码 this gt load gt library array pdf ciqrcode data
  • 如何解码包含无效字节的字节对象,Python3

    在python2中 我可以整天生成以字符串格式表示的这些十六进制字节 x00 xaa xff gt gt gt 00 decode hex aa decode hex ff decode hex gt gt gt x00 xaa xff 同
  • 为什么 2 和 4 在 b 之前打印?

    function first return new Promise resolve gt console log 2 resolve 3 console log 4 async function f console log 1 let r
  • 如何使用用户提供的 Hadoop 正确配置 Spark 2.4

    我想使用 Spark 2 4 5 当前稳定的 Spark 版本 和 Hadoop 2 10 2 x 系列中当前稳定的 Hadoop 版本 此外 我需要访问 HDFS Hive S3 和 Kafka http spark apache org
  • 引导多个 angular2 模块时出错

    当我们更新应用程序的某些部分时 我们开始将当前的应用程序转换为 Angular2 所以我们正在尝试用 Angular2 模块 组件替换应用程序的某些部分 第一部分是创建两个不同的搜索组件并将它们放置在 asp net mvc 中的不同视图中
  • grails 更改 gsp 视图中的日期格式

    当我尝试在 gsp 视图中使用日期格式标记来更改日期格式时 但它不起作用 这是我的代码 class MyDate Date date 我的日期控制器 def unixSeconds params date replaceAll as lon
  • 我可以使用Treetop来解析IO吗?

    我有一个文件想要用 Treetop 解析 如果我想解析整个事情 我会使用 rule document category listing end 我真的不想立即将整个文件读入内存 我知道我可以设置解析器来解析一个category listin
  • MySQL 中的行版本控制

    我想在表中包含一个整数版本字段 在每次更新行时自动递增 在 MySQL 中可以做到这一点吗 请注意 我不是在谈论TIMESTAMP 这是不可靠的 因为同一秒内可能会发生两个并发更新 是的 更一般的问题称为缓慢改变尺寸 http en wik
  • 在强类型 MVC 视图用户控件中使用值类型

    我有一个具有以下基本结构的 MVC 用户控件 当我使用它时 它给出了这个错误消息 编译器错误消息 CS0452 类型 decimal 必须是引用 输入以便将其用作参数 泛型类型或方法中的 TModel System Web Mvc View
  • 如何使用 Nokogiri 访问属性

    我有一个访问某些属性的值的简单任务 这是一个简单的脚本 使用Nokogiri XML Builder创建一个简单的 XML 文档 require nokogiri builder Nokogiri XML Builder new encod
  • 如何在子线程中继续ThreadLocal的对象?

    我在 ThreadLocal 中传递了一个对象 现在我当前的线程将创建新的子线程 我希望 ThreadLocal 中的对象也应该继续使用子线程 有什么办法可以做到这一点吗 先感谢您 你需要的是一个InheritableThreadLocal
  • 这个计算 a^n 的算法是如何重写以在 O(log n) 时间内运行的?

    Suppose you want to compute an A simple algorithm would multiply a n times as follows result 1 for int i 1 i lt n i resu
  • TypeScript - 是否可以根据模式匹配甚至长度来验证字符串类型?

    考虑以下组件 它使用一个名为的库styled components创建一个预样式Text成分 const StyledText styled Text font family Roboto color props ITextProps gt