我需要制作一个递归样式对象,该对象可以支持样式属性并采用嵌套格式。
我很难解决这个问题,并且我已经尝试了所有可以在SO和google上找到的解决方案。
interface Properties {
border?: string;
width?: string;
}
//# 1 Type attempt
type TRecursiveProperties = Properties & {
[index: string]: TRecursiveProperties;
};
//# 2 Interface attempt
interface IRecursiveProperties extends Properties {
[index: string]: IRecursiveProperties;
}
const test: TRecursiveProperties = {
border: '1px solid green',
isActive: {
border: '2px solid red',
'&:hover': {
border: '3px solid blue'
}
}
};
我希望递归属性是一种回退/捕获所有或某种方式来从Properties对象中排除键的方法。
我遇到的两个错误都是
类型别名'TRecursiveProperties'循环引用自身。
类型'string'的属性'width'不能分配给字符串索引类型'IRecursiveProperties'
有什么想法可以实现这一目标吗?
答案 0 :(得分:1)
我会这样做:
interface Properties {
width?: string;
border?: string;
[selector: string]: string | Properties | undefined;
}
const myStyles: Properties = {
'width': '100px',
' .child': {
'width': '200px',
'border': '1px color blue',
'&:hover': {
border: '1px solid aquamarine',
},
},
};
在此打字稿资源:https://basarat.gitbooks.io/typescript/docs/types/index-signatures.html中,搜索“设计模式:嵌套索引签名”以查看非常相似的示例。
答案 1 :(得分:1)
没有一种具体的类型可以准确地表示您要执行的操作:即“特殊情况”某些属性并将其从索引签名中排除。它已经requested,但是到目前为止还没有办法。
请注意,我说过没有具体类型。您可以将其表示为将值约束到的泛型类型。因此,您不必拥有类型RecursiveProperties
的值,而拥有类型T extends VerifyRecursiveProperties<T>
的值。像这样:
type VerifyRecursiveProperties<T> = Properties & { [K in Exclude<keyof T, keyof Properties>]:
T[K] extends object ? VerifyRecursiveProperties<T[K]> : never }
然后您需要一个辅助函数来推断特定的T
,而不必自己写出来:
const asRecursiveProperties = <T extends VerifyRecursiveProperties<T>>(t: T) => t;
这使您可以执行想要的操作:
const test = asRecursiveProperties({
border: '1px solid green',
isActive: {
border: '2px solid red',
'&:hover': {
border: '3px solid blue'
}
}
}); // okay
,如果违反约束,还会给出错误:
asRecursiveProperties({
border: 1 // error, number is not string
})
asRecursiveProperties({
isActive: "" // error, string is not never
})
asRecursiveProperties({
foo: {
bar: {
baz: {
border: 1, // error, number is not string
}
}
}
})
如果这太复杂了,您可能想要放松约束以允许索引签名接受string | undefined
(如the other answer),或者重构您的类型,以免您尝试将您的Properties
属性推入与递归属性相同的对象中,如下所示:
interface RefactoredRecursiveProperties extends Properties {
nested?: { [k: string]: RefactoredRecursiveProperties }
}
const test2: RefactoredRecursiveProperties = {
border: '1px solid green',
nested: {
isActive: {
border: '2px solid red',
nested: {
'&:hover': {
border: '3px solid blue'
}
}
}
}
}
这种重构对您来说可能不是理想的选择,但是对于编译器来说,重构要简单得多。
好的,希望能有所帮助;祝你好运!