我有以下类型:
type Example = {
key1: number,
key2: string
}
,我需要基于Example
类型创建类型,以成为key: value
对之一。当然,我正在寻找通用解决方案。这是此类型应返回的内容:
type Example2 = { ... };
const a: Example2 = { key3: 'a' } // incorrect
const b: Example2 = { key1: 'a' } // incorrect
const c: Example2 = { key2: 1 } // incorrect
const d: Example2 = { key1: 1 } // correct
const e: Example2 = { key2: 'a' } // correct
const f: Example2 = { key1: 1, key2: 'a' } // incorrect
我正在尝试使用它:
type GetOne<T> = { [P in keyof T]: T[P] };
type Example2 = GetOne<Example>;
但是它返回所有属性和示例,其中const f
无法正常工作。
答案 0 :(得分:1)
我们将生成所有可能性的组合:
type Example = {
key1: number,
key2: string
}
type PickOne<T> = { [P in keyof T]: Record<P, T[P]> & Partial<Record<Exclude<keyof T, P>, undefined>> }[keyof T]
type Example2 = PickOne<Example>;
const a: Example2 = { key3: 'a' } // incorrect
const b: Example2 = { key1: 'a' } // incorrect
const c: Example2 = { key2: 1 } // incorrect
const d: Example2 = { key1: 1 } // correct
const e: Example2 = { key2: 'a' } // correct
const f: Example2 = { key1: 1, key2: 'a' } // incorrect
我们这样做的方法是,首先创建一个新类型,对于每个键,我们都有一个仅带有该键的object属性(暂时忽略& Partial<Record<Exclude<keyof T, P>, undefined>>
)。因此,{ [P in keyof T]: Record<P, T[P]> }
例如:
type Example2 = {
key1: Record<"key1", number>;
key2: Record<"key2", string>;
}
然后使用索引操作[keyof T]
来获取这种新类型中所有值的并集,因此我们得到Record<"key1", number> | Record<"key2", string>
此类型将适用于除最后一个测试之外的所有测试,在该测试中,您不允许原始类型具有多个属性。由于多余的属性检查与联合类型(see)一起使用的方式,如果任何联合组成部分中存在密钥,它将允许密钥。
为解决此问题,我们将Record<P, T[P]>
与一种类型相交,该类型可选地包含其余属性(Exclude<keyof T, P>
),但强制将所有属性都设为undefined
。
答案 1 :(得分:0)
也可以通过以下代码实现:
export type PickOne<T> = {
[P in keyof T]?: Record<P, T[P]>
}[keyof T]
type Example = {
key1: number;
key2: string;
}
type Example2 = PickOne<Example>;
const a: Example2 = { key1: 1 } // correct
const b: Example2 = { key1: "1" } // incorrect - string cannot be assigned to number
const c: Example2 = { key2: 'a' } // correct
const d: Example2 = { key3: 'a' } // incorrect - unknown property