提问者:小点点

联合类型的部分<CssStyle声明>和字典导致键入问题,没有隐含的任何标志


由于可以使用VueJSv-bind: style绑定设置CSS变量,我试图创建一个联合类型,其中传递给v-bind: style的对象保留了CssStyleDelcaration的类型,但足够轻松接受任意属性名称:

type Dictionary<T> = { [key: string]: T };
type Nullable<T> = T | null;
type CssStyleObject =
  Partial<CSSStyleDeclaration> |
  Dictionary<Nullable<string>>;

实现的一个例子是这样的(请参阅TypeScript playground上的实时代码):

<!-- Template -->
<div v-bind:style="myStyle"></div>
// Component code
@Component
export default class MyComponent extends Vue {
  public get myStyle(): CssStyleObject {
    const style: CssStyleObject = { };
    style.backgroundColor = 'red';
    style['--my-custom-css-property'] = '16px';
  }
}

但是,当我启用了noInInimplatiany标志(由于项目范围的配置,我无法关闭该标志)时,我会出现类型错误,因为TypeScript会抱怨:

元素隐式具有“any”类型,因为类型“CssStyleObject”没有索引签名。

我在这里看到了一个建议的解决方案:当编译类型脚本时,如果没有启用任何标志,我如何防止错误对象类型的索引签名隐含地具有'any'类型?,但是如果有另一个,我很想避免简单地转换为any可行的解决方案是可能的。

有趣的是,在分配给样式变量时,一旦使用自定义属性名,错误消息就会消失:

const style: CssStyleObject = {
    '--foobar': '50%'
};
style.backgroundColor = 'red';
style['--my-custom-css-property'] = '16px';

请参阅上面TypeScript Playground上的代码。

我怀疑这是因为类型为样式然后以某种方式修改为简单的字典

所以,事实证明我天生就混淆了TypeScript中的交集和并集类型。在这种情况下,CssStyleObjectPartial的交点

type Dictionary<T> = { [key: string]: T };
type Nullable<T> = T | null;

// Use `&` for creating an intersection type!
type CssStyleObject =
  Partial<CSSStyleDeclaration> &
  Dictionary<Nullable<string>>;

共1个答案

匿名用户

首先,您的代码的当前行为是因为区分的联合类型的工作方式。CSSStyle声明没有索引签名,而字典有。因此,当您在声明中添加自定义属性时,该类型被推断为字典

其次,如果要向现有类型添加索引,则不应使用联合类型。您应该改用交叉点类型。也就是说,CssStyleObject是一个CSSStyleDeclaration并具有索引签名,但不是一个CssStyleObject或具有索引签名的对象

最后,这里是工作代码

type CssStyleObject = Partial<CSSStyleDeclaration> & Record<string, string | null>
// or 
interface CssStyleObject extends Partial<CSSStyleDeclaration> {
    [key: string]: string | null
}