我有一个类型定义,允许我通过表示对象或嵌套数组的键的字符串/索引数组来导航对象:
export type PredicateFunction<ArrayType> = (array: ArrayType, index?: number) => boolean;
export type IndexOrPredicateFunction<Type> = number | PredicateFunction<Type>;
export type StatePathKey = IndexOrPredicateFunction<any> | string;
export type StatePath<Obj, Path extends (string | IndexOrPredicateFunction<any>)[] = []> =
object extends Obj
? Path
: Obj extends object
? (Path |
// Check if object is array
(Obj extends readonly any[] ?
// ...when array only allow index or PredicateFunction
StatePath<Obj[number], [...Path, IndexOrPredicateFunction<Obj[number]>]>
// ...when object generate type of all possible keys
: { [Key in string & keyof Obj]: StatePath<Object[Key], [...Path, Key]> }[string & keyof Obj]))
: Path;
这适用于例如这个界面:
interface State1 {
test: {
nestedTest: boolean
}
}
像这样:
const t1: StatePath<State1> = ['test', 'nestedTest'];
但是一旦我有了可选属性,它就会崩溃:
interface State2 {
test: {
nestedTest?: boolean
}
}
知道如何解决这个问题吗?我已经尝试在该类型上使用
-?
但没有成功。
在此处查找用于复制的沙箱:Typescript Playground
解决此特定问题的最简单方法是将支票从
object extends Obj
更改为 object extends Required<Obj>
。如果 Obj
结果是一个 弱类型,这意味着它是一个对象类型,其中 all 的属性都是 可选,那么 TypeScript 将看到空对象类型 {}
和 object
类型可分配给它。 例如,object extends {a?: string, b?: number}
是 true。但随后该类型会在您不希望它出现的地方退出。
Required<T>
实用程序类型,您可以将 object
与需要可选属性的类型版本进行比较。虽然 object extends {a?: string, b?: number}
为 true,但 object extends Required<{a?: string, b?: number}>
(又名 object extends {a: string, b: number}
)为 false。 因此,现在该类型将不会退出,除非 Obj
确实为空,或 object
,或 unknown
等。