如何使用映射类型表达“至少一个现有属性并且没有其他属性”

rob*_*kuz 3 typescript mapped-types

请原谅我稍微长一点的标题。

给定以下类型

type A = {
    foo: string;
    bar: number;
    baz: boolean;
}
Run Code Online (Sandbox Code Playgroud)

我喜欢创造一个新的“部分”B型

type B = Partial<A>
Run Code Online (Sandbox Code Playgroud)

这样 B 必须至少包含 A 的属性之一,并且只允许 A 的属性

//compiles
const b1 = {
   foo: "yeah"
}

//errors
const b2 = {}
const b3 = {lala: "lala"}
const b4 = {foo: "foo is alowed", but_not_this: false}
Run Code Online (Sandbox Code Playgroud)

cap*_*ian 7

type A = {
  foo: string;
  bar: number;
  baz: boolean;

}
type AtLeastOne<Obj, Keys = keyof Obj> = Keys extends keyof Obj ? Pick<Obj, Keys> : never

type NonEmpty<T> = Partial<T> & AtLeastOne<T>

// Partial<A> & (Pick<A, "foo"> | Pick<A, "bar"> | Pick<A, "baz">)
type Result = NonEmpty<A>

//compiles
const b1: Result = {
  foo: "yeah"
}

//errors
const b2: Result = {}
const b3: Result = { lala: "lala" }
const b4: Result = { foo: "foo is alowed", but_not_this: false }
Run Code Online (Sandbox Code Playgroud)

操场

解释

Partial<A> & Pick<A, "foo"> | Pick<A, "bar"> | Pick<A, "baz">这是您最终应该达到的最低要求类型。

首先我们需要确保该对象不为空。它应该具有三个道具中的任何一个。

考虑分配条件类型

type AtLeastOne<Obj, Keys = keyof Obj> = Keys extends keyof Obj ? Pick<Obj, Keys> : never

Run Code Online (Sandbox Code Playgroud)

根据文档,Pick<Obj, Keys>- 将应用于每个键。因此,AtLeastOne返回Pick<A, "foo"> | Pick<A, "bar"> | Pick<A, "baz">

现在是最简单的部分,您只需要使用交集来合并AtLeastOneand的返回类型Partial<A>

type NonEmpty<T> = Partial<T> & AtLeastOne<T>

Run Code Online (Sandbox Code Playgroud)

您可以在我的打字稿博客中找到更多有趣的示例