gpt4 book ai didi

typescript :有递归keyof吗?

转载 作者:行者123 更新时间:2023-12-04 14:39:30 24 4
gpt4 key购买 nike

有没有办法让这样的代码编译并保持类型安全?

type ComplexObject = {
primitive1: boolean;
complex: {
primitive2: string;
primitive3: boolean;
}
};

interface MyReference {
myKey: keyof ComplexObject;
}

const works1: MyReference = {
myKey: "primitive1"
}

const works2: MyReference = {
myKey: "complex"
}

const iWantThisToCompile1: MyReference = {
myKey: "complex.primitive2" // Error: Type '"complex.primitive2"' is not assignable to type '"primitive1" | "complex"'.
}

const iWantThisToCompile2: MyReference = {
myKey: "complex['primitive3']" // Error: Type '"complex['primitive3']"' is not assignable to type '"primitive1" | "complex"'.
}

// const iDontWantThisToCompile1: MyReference = {
// myKey: "primitive2"
// }

// const iDontWantThisToCompile2: MyReference = {
// myKey: "primitive3"
// }
您可以使用此代码 here .

最佳答案

这可以通过 TypeScript 4.1 中的新模板文字类型和递归类型实现。 .
属性和索引访问类型
这里有几种定义它的方法,可以超越单一级别。我推荐第一种方法,因为它的公共(public) API 中没有额外的未使用类型参数。

export type RecursiveKeyOf<TObj extends object> = {
[TKey in keyof TObj & (string | number)]:
RecursiveKeyOfHandleValue<TObj[TKey], `${TKey}`>;
}[keyof TObj & (string | number)];

type RecursiveKeyOfInner<TObj extends object> = {
[TKey in keyof TObj & (string | number)]:
RecursiveKeyOfHandleValue<TObj[TKey], RecursiveKeyOfAccess<TKey>>;
}[keyof TObj & (string | number)];

type RecursiveKeyOfHandleValue<TValue, Text extends string> =
TValue extends object
? Text | `${Text}${RecursiveKeyOfInner<TValue>}`
: Text;

type RecursiveKeyOfAccess<TKey extends string | number> =
| `['${TKey}']`
| `.${TKey}`;
export type RecursiveKeyOf<TObj extends object, isFirstLevel extends boolean = true> = {
[TKey in keyof TObj & (string | number)]:
isFirstLevel extends true
? RecursiveKeyOfHandleValue<TObj[TKey], `${TKey}`>
: RecursiveKeyOfHandleValue<TObj[TKey], RecursiveKeyOfAccess<TKey>>;
}[keyof TObj & (string | number)];

type RecursiveKeyOfHandleValue<TValue, Text extends string> =
TValue extends object
? Text | `${Text}${RecursiveKeyOf<TValue, false>}`
: Text;

type RecursiveKeyOfAccess<TKey extends string | number> =
| `['${TKey}']`
| `.${TKey}`;
仅属性访问类型
如果您只需要访问属性,那就简单多了:
export type RecursiveKeyOf<TObj extends object> = {
[TKey in keyof TObj & (string | number)]:
TObj[TKey] extends object
? `${TKey}` | `${TKey}.${RecursiveKeyOf<TObj[TKey]>}`
: `${TKey}`;
}[keyof TObj & (string | number)];
解释和分解
export type RecursiveKeyOf<TObj extends object> = (
(
// 1. Create an object type from `TObj`, where all the individual
// properties are mapped to a string type if the value is not an object
// or union of string types containing the current and descendant
// possibilities when it's an object type.
{
// Does this for every property in `TObj` that is a string or number
[TPropName in keyof TObj & (string | number)]:
HandleProperty<TObj[TPropName], TPropName>;
}
)[
keyof TObj & (string | number) // for every string or number property name
] // 2. Now flatten the object's property types to a final union type
);

type HandleProperty<TValue, TPropName extends string | number> =
// If the value of the property is an object type...
TValue extends object
// Then...
// 1. Return the current property name as a string
? `${TPropName}`
// 2. And return the property name concatenated with a `.` and
// all the return values of `RecrusiveKeyOf<TValue>`
| `${TPropName}.${RecursiveKeyOf<TValue>}`
// Else, only return the current property name as a string
: `${TPropName}`;
例如:
// this type
{
prop: { a: string; b: number; };
other: string;
}

// goes to
{
prop: "prop" | "prop.a" | "prop.b";
other: "other";
}

// goes to
"prop" | "prop.a" | "prop.b" | "other"

关于 typescript :有递归keyof吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65332597/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com