Typeguard不会缩小字体

问题描述

我正在创建一个对象来存储一堆RGB颜色,并且允许嵌套。因此,在遍历对象时,我需要查看哪些键对应于RGB值或对象。但是,我尝试过的每个类型防护实际上都不会缩小类型。

type Color = [number,number,number] | 'transparent'
type ColorGroup = Record<string,Color>
type Colors = Record<string,Color | ColorGroup>

const colors: Colors = {
    black: [0,0],white: [255,255,255],transparent: 'transparent',primary: {
        '50': [211,233,252],'100': [179,213,248],'200': [127,185,251],'300': [68,156,253],'400': [0,126,254],'500': [13,100,226],'600': [17,79,189],'700': [15,62,157],'800': [10,46,122],'900': [1,22,77],}
}

const isColor = (color: Color | ColorGroup): color is Color => {
    return Array.isArray(color) || typeof color === 'string'
}

const usesColor = (color: Color):void => {
    // does something with the color
}

for(const color in colors) {
    if(isColor(colors[color])) usesColor(colors[color]) // error: type 'Record<string,Color>' is not assignable to type 'Color'
}

Playground link

有什么想法吗?我只是缺少有关类型保护的基本知识吗?

解决方法

您在TypeScript中遇到了设计限制。有关更多信息,请参见microsoft/TypeScript#33391microsoft/TypeScript#31445

问题在于,除非这些属性是字符串文字或数字文字,否则编译器不会跟踪属性类型保护的结果:

if (isColor(colors.black)) usesColor(colors.black); // okay

不是(如果它是存储在变量中的值)

if (isColor(colors[color])) usesColor(colors[color]) // error!

在访问colors[color]时,编译器仅知道color是类型string的变量。在类型防护之后,您再次访问colors[color],但是编译器没有意识到您之前已经检查过它,因为color只是它的某些string类型变量。从某种意义上说,编译器看不到您的代码与以下代码之间的区别:

declare const color1: string;
declare const color2: string;
if (isColor(colors[color1])) usesColor(colors[color2]); // error!

这不是类型防护的好用。

以上链接的问题提到,虽然支持这样的代码会很好,但是就编译器资源而言,这非常昂贵。跟踪将哪些变量用作索引是很多额外的工作,而且几乎总是不必要的工作。这里的用例显然不值得...尤其是因为:


有一个小的重构可以提供您想要的行为。代替执行多个索引操作,而是执行单个索引操作并将其保存到其自己的变量中,如下所示:

for (const color in colors) {
    const c = colors[color];
    if (isColor(c)) usesColor(c) // okay
}

由于c是其自己的变量,因此不再需要担心带有string的索引。编译器可以轻松地使用c上的类型防护来缩小c的类型。因此,您可以获得所需的行为,但牺牲了较少的惯用JavaScript。

Playground link to code

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...