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

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

问题描述

我们的结构如下:

 出口类型LinkRestSource = {
model:string;
rel ?: string;
title?:string;
} | {
model?:string;
rel:string;
title?:string;
} | {
model?:string;
rel ?: string;
title:string;
};

这与说法几乎相同

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

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

中传递如何创建类似于部分的泛型,但其行为与上面的结构相似?

解决方案

我想我有一个适合您的解决方案。您正在寻找一些类型为 T 的东西,并生成一个相关类型,其中至少包含 属性< T 。也就是说,它就像部分< T> ,但不包括空对象。

如果是这样,这里是:

  type AtLeastOne   

解析它:首先, AtLeastOne< T> 部分< T> 相交。 U [keyof U] 表示它是 U 的所有属性值的联合。我已经定义(默认值) U 映射类型,其中 T 的每个属性映射到 Pick< T ,K> ,这是键 K 的单一属性类型。 (例如, Pick< {foo:string,bar:number},'foo'> 相当于 {foo:string} ...它从原始类型中挑选'foo'属性。)含义 U [keyof U] 在这种情况下是来自 T 的所有可能的单一财产类型的联合。



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

 类型FullLinkRestSource = {
model:串;
rel:string;
title:string;
}

type LinkRestSource = AtLeastOne< FullLinkRestSource>

扩展为

  type LinkRestSource = AtLeastOne< FullLinkRestSource,{
[Key in FullFRestSource]中的K:Pick< FullLinkRestSource,K>
}>

  type LinkRestSource = AtLeastOne< FullLinkRestSource,{
model:Pick< FullLinkRestSource,'model'> ;,
rel:Pick< FullLinkRestSource,'rel'> ;,
title:选择< FullLinkRestSource,'标题'>
}>

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

  type LinkRestSource =部分< FullLinkRestSource> &安培; {
模型:{model:string},
rel:{rel:string},
title:{title:string}>
} [keyof {
model:{model:string},
rel:{rel:string},
title:{title:string}>
}]

  type LinkRestSource =部分< FullLinkRestSource> &安培; {
模型:{model:string},
rel:{rel:string},
title:{title:string}>
} ['model'| 'rel'| 'title']

  type LinkRestSource =部分< 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}



你可以测试它:

  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 = {//缺少属性
const错误1:LinkRestSource = {model:'a',titel:'c'} //字符串文字的额外属性

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


We have structure that is like the following:

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

Which is almost the same as saying

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

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

解决方案

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.

If so, here it is:

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

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>

That expands to

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

or

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

or

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

or

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

or

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

or

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

or

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

or

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.

You can test it out:

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天全站免登陆