typescript 如果提供了一组可选键,则将其设置为必需

6za6bjd0  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(89)

我想在TS中创建一个实用程序类型,它应该有两个泛型类型参数。它应该为第一个泛型类型参数创建所有必需的键。第二个泛型类型参数的键应该是可选的,但如果至少设置了其中一个,则所有键都是必需的。

type RequiredAndAllOrNothing<R, S> = { /* How? */ }
// example
type Example = RequiredAndAllOrNothing<
  { aaaa: number; bbbb: boolean; cccc: boolean},
  { dddd: number; eeee: boolean; ffff: boolean }
>
// should be ok:
const x: Example = { aaaa: 1, bbbb: true, cccc: false }
const y: Example = { aaaa: 1, bbbb: true, cccc: false, dddd: 1, eeee: true, ffff: false, }
// should not be ok, dddd was provided but neither eeee nor ffff
const z: Example = { aaaa: 1, bbbb: true, cccc: false, dddd: 1, }

我试过这种幼稚的方法,但不起作用

// Same result as just Required<R & S>
type RequiredAndAllOrNothing<R, S> = Required<R> & (Required<S> | Record<string, never>)

尽管这部分做了它应该做的:

// accept object if it has all the properties or if it is empty
type AllOrNothing<T> = Required<T> | Record<string, never>

我错过了什么?

eaf3rand

eaf3rand1#

type EnsureKeysAreMissing<T> = { [K in keyof T]?: never }

这里的EnsureKeysAreMissing类型创建了一个对象类型,其中每个键都必须缺失,这是“nothing”的情况。
“all”只是输入。
我们用这个公式:

type RequiredAndAllOrNothing<R, S> = R & (EnsureKeysAreMissing<S> | S)

由于R是必需的部分,因此我们可以直接使用它而无需修改。
然后我们将&与两个可能类型的并集相交。
一个成员是上面描述的EnsureKeysAreMissing<S> a。
这个并集的另一个成员就是S,我们可以直接使用它。

// example
type Example = RequiredAndAllOrNothing<
  { a: number; b: boolean; c: boolean },
  { d: number; e: boolean; f: boolean }
>

// should be ok:
const x: Example = { a: 1, b: true, c: false }
const y: Example = { a: 1, b: true, c: false, d: 1, e: true, f: false, }

// should not be ok, d was provided but neither e nor f
const z: Example = { a: 1, b: true, c: false, d: 1, }
/*
Type '{ a: number; b: true; c: false; d: number; }' is not assignable to type 'Example'.
  Type '{ a: number; b: true; c: false; d: number; }' is not assignable to type '{ a: number; b: boolean; c: boolean; } & { d: number; e: boolean; f: boolean; }'.
    Type '{ a: number; b: true; c: false; d: number; }' is missing the following properties from type '{ d: number; e: boolean; f: boolean; }': e, f(2322)
*/

见Playground

相关问题