typescript - 如何在 Typescript 定义中表示对象键替换?
问题描述
目前我有以下内容types
:
type PossibleKeys = number | string | symbol;
type ValueOf<T extends object> = T[keyof T];
type ReplaceKeys<T extends Record<PossibleKeys, any>, U extends Partial<Record<keyof T, PossibleKeys>>> =
Omit<T, keyof U> & { [P in ValueOf<U>]: T[keyof U] };
...但是,尽管它甚至可以部分工作,但它给出了以下错误:
类型 'U[keyof U]' 不能分配给类型 'string | 号码 | 象征'。
interface Item {
readonly description: string;
readonly id: string;
}
interface MyInterface {
readonly id: string;
readonly propToReplace: number;
readonly anotherPropToReplace: readonly Item[];
}
type ReplacedUser = ReplaceKeys<MyInterface, { propToReplace: 'total', anotherPropToReplace: 'items' }>;
在ReplacedUser
我可以看到类型几乎是正确的。推断类型为:
{ id: string; total: number | readonly Item[]; items: number | readonly Item[]; }
...虽然我期待:
{ id: string; total: number; items: readonly Item[]; }
我究竟做错了什么?我想首先知道如何表达P
需要传入的值U
以抑制 Typescript 错误,然后为特定的value
.
解决方案
最简单的方法是反转U
您的类型参数ReplaceKeys
:
type PossibleKeys = number | string | symbol;
type ReplaceKeys<T extends {}, U extends Record<PossibleKeys, keyof T>> = Omit<T, ValueOf<U>> & {
[K in keyof U]: T[U[K]]
};
然后您可以像这样使用它:
type ReplacedUser = ReplaceKeys<MyInterface, { total: 'propToReplace', items: 'anotherPropToReplace' }>;
如果你不能改变U
事物的形状变得有点棘手:
// Example types from your post
interface Item {
readonly description: string;
readonly id: string;
}
interface MyInterface {
readonly id: string;
readonly propToReplace: number;
readonly anotherPropToReplace: readonly Item[];
}
// All possible key types
type PossibleKeys = number | string | symbol;
// Helper type to get all non-nullable values from type T
type DefinedValues<T> = NonNullable<T[keyof T]>;
// Helper type for your replacements object - a record whose values are valid keys
// and whose keys are also present in type T (the input type)
//
// Partial is used to make sure you don't need to pass all keys of T in your replacements
type Replacements<T extends {}> = Partial<Record<keyof T, PossibleKeys>>;
// Helper type that swaps object keys for values
type Invert<T extends Replacements<C>, C extends {} = {}> = {
[N in DefinedValues<T>]: {
[K in keyof T]: N extends T[K] ? K : never
}[keyof T]
}
type ReplacedKeys<T extends {}, R extends Replacements<T>> = Omit<T, keyof R | DefinedValues<R>> & {
[N in keyof Invert<R>]: {
[L in keyof R]: N extends R[L] ? (L extends keyof T ? T[L] : never) : never;
}[keyof R]
}
请注意,使用第二种方法不会警告您有重复的映射:
type ReplacedUser = ReplacedKeys<MyInterface, { propToReplace: 'total', anotherPropToReplace: 'total' }>;
检查这里的操场。
推荐阅读
- python - Python Pyfolio PYMC3 ValueError
- angular - Angular Material - 解析路线后分页不起作用
- google-chrome - 为什么chrome渲染不同的unicode字符””(U+2F804)”和你”(U+4F60)是同一个字符
- android - 是否可以使用 MotionLayout 将不同的持续时间应用于 ConstraintSet 中的不同约束?
- mysql - 为什么append的最后一句在web上没有显示?
- php - “登录”脚本混乱情况下的 SQL 查询问题
- tensorflow-serving - 使用 NMT 进行 TF 服务
- nltk - 如何修复python中的nltk stanford导入错误
- linux - 在日志文件中找到某个字符串时停止 Tail
- java - 如何在java中处理更改的方法签名