如何创建需要设置单个属性的 Partial-like [英] How to create a Partial-like that requires a single property to be set

查看:25
本文介绍了如何创建需要设置单个属性的 Partial-like的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的结构如下:

export type LinkRestSource = {
    model: string;
    rel?: string;
    title?: string;
} | {
    model?: string;
    rel: string;
    title?: string;
} | {
    model?: string;
    rel?: string;
    title: string;
};

这和说的差不多

type LinkRestSource = Partial<{model: string, rel: string, title: string}>

除了这将允许传入一个空对象,而初始类型需要传入其中一个属性

Except that this will allow an empty object to be passed in whereas the initial type requires one of the properties to be passed in

我怎样才能创建一个像 Partial 这样的泛型,但它的行为就像我上面的结构?

How can I create a generic like Partial, but that behaves like my structure above?

推荐答案

我想我有一个解决方案.您正在寻找采用 T 类型并生成包含 至少一个 T 属性的相关类型的东西.也就是说,它就像 Partial 但排除了空对象.

I think I have a solution for you. You're looking for something that takes a type T and produces a related type which contains at least one property from T. That is, it's like Partial<T> but excludes the empty object.

如果是这样,这里是:

type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]

剖析它:首先,AtLeastOnePartialsomething 相交.U[keyof U] 表示它是 U 的所有属性值的并集.我已经将(默认值)U 定义为 映射类型,其中 T 的每个属性都映射到 Pick,键的单一属性类型K.(例如,Pick<{foo: string, bar: number},'foo'> 等价于 {foo: string}... 它选择"来自原始类型的 'foo' 属性.)这意味着 U[keyof U] 在这种情况下是来自 T 的所有可能的单属性类型的联合.

To dissect it: first of all, AtLeastOne<T> is Partial<T> intersected with something. U[keyof U] means that it's the union of all property values of U. And I've defined (the default value of) U to be a mapped type where each property of T is mapped to Pick<T, K>, a single-property type for the key K. (For example, Pick<{foo: string, bar: number},'foo'> is equivalent to {foo: string}... it "picks" the 'foo' property from the original type.) Meaning that U[keyof U] in this case is the union of all possible single-property types from T.

嗯,这可能令人困惑.让我们一步一步地看看它是如何在以下具体类型上运行的:

Hmm, that might be confusing. Let's see step-by-step how it operates on the following concrete type:

type FullLinkRestSource = {
  model: string;
  rel: string;
  title: string;
}

type LinkRestSource = AtLeastOne<FullLinkRestSource>

扩展为

type LinkRestSource = AtLeastOne<FullLinkRestSource, {
  [K in keyof FullLinkRestSource]: Pick<FullLinkRestSource, K>
}>

type LinkRestSource = AtLeastOne<FullLinkRestSource, {
  model: Pick<FullLinkRestSource, 'model'>,
  rel: Pick<FullLinkRestSource, 'rel'>,
  title: Pick<FullLinkRestSource, 'title'>
}>

type LinkRestSource = AtLeastOne<FullLinkRestSource, {
  model: {model: string},
  rel: {rel: string},
  title: {title: string}>
}>

type LinkRestSource = Partial<FullLinkRestSource> & {
  model: {model: string},
  rel: {rel: string},
  title: {title: string}>
}[keyof {
  model: {model: string},
  rel: {rel: string},
  title: {title: string}>
}]

type LinkRestSource = Partial<FullLinkRestSource> & {
  model: {model: string},
  rel: {rel: string},
  title: {title: string}>
}['model' | 'rel' | 'title']

type LinkRestSource = Partial<FullLinkRestSource> &
  ({model: string} | {rel: string} | {title: string})

type LinkRestSource = {model?: string, rel?: string, title?: string} & 
  ({model: string} | {rel: string} | {title: string})

type LinkRestSource = { model: string, rel?: string, title?: string } 
  | {model?: string, rel: string, title?: string} 
  | {model?: string, rel?: string, title: string}

我想,这就是你想要的.

which is, I think, what you want.

你可以测试一下:

const okay0: LinkRestSource = { model: 'a', rel: 'b', title: 'c' }
const okay1: LinkRestSource = { model: 'a', rel: 'b' }
const okay2: LinkRestSource = { model: 'a' }
const okay3: LinkRestSource = { rel: 'b' }
const okay4: LinkRestSource = { title: 'c' }

const error0: LinkRestSource = {} // missing property
const error1: LinkRestSource = { model: 'a', titel: 'c' } // excess property on string literal

那么,这对你有用吗?祝你好运!

So, does that work for you? Good luck!

这篇关于如何创建需要设置单个属性的 Partial-like的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆