gpt4 book ai didi

Typescript 类型,其中对象完全由一组可能属性的单个属性组成

转载 作者:行者123 更新时间:2023-12-04 14:14:06 24 4
gpt4 key购买 nike

我正在尝试使用类型系统对特定模式进行建模,其中对象完全由一组可能属性的单个属性组成。

换句话说,该类型将是部分类型,但只允许一个属性。

interface PossibleProperties {
cat?: AllPropsOfSameType;
dog?: AllPropsOfSameType;
cow?: AllPropsOfSameType;
}

interface ShouldBeExactlyOneOfPossibleProperties {
[P in keyof PossibleProperties]: AllPropsOfSameType; // Wupz, this allows for 0 or more...
}

我见过 solutions需要至少一个属性:

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

但我需要类似 AtMostOne<T, U = {[K in keyof T]: Pick<T, K> }> 的东西或 ExactlyOne<T, U = {[K in keyof T]: Pick<T, K> }>这可能是 AtMostOne 的交集类型和 AtLeastOne
如果可能的话,有什么想法吗?

最佳答案

我的第一个想法是创建一个联合类型,例如:

type ExactlyOne =
{ cat?: AllPropsOfSameType } |
{ dog?: AllPropsOfSameType } |
{ cow?: AllPropsOfSameType };

可以使用 distributive conditional types :

type ExactlyOne<T, TKey = keyof T> = TKey extends keyof T ? { [key in TKey]: T[TKey] } : never;
type ShouldBeExactlyOneOfPossibleProperties = ExactlyOne<PossibleProperties>;

Playground

但它仍然允许分配具有多个属性的对象:

// this assignment gives no errors
const animal: ShouldBeExactlyOneOfPossibleProperties = {
cat: 'a big cat',
dog: 'a small dog'
};

这是因为 TypeScript 中的联合类型是包含性的,您目前无法创建独占联合类型。看到这个 answer .

所以我们需要以某种方式禁止额外的属性。一个选项可能是使用 never类型,但不幸的是,不可能创建类型为 never 的可选属性。因为 never | undefinedundefined .如果可以的话 undefined您可以使用以下可怕的类型的其他属性:

type ExactlyOne<T, TKey = keyof T> = TKey extends keyof T
? { [key in Exclude<keyof T, TKey>]?: never } & { [key in TKey]: T[key] }
: never;

结果类型如下所示:

({
dog?: undefined;
cow?: undefined;
} & {
cat: string | undefined;
}) | ({
cat?: undefined;
cow?: undefined;
} & {
dog: string | undefined;
}) | ({
cat?: undefined;
dog?: undefined;
} & {
cow: string | undefined;
})

这太可怕了……但它接近预期。

Playground

这种方法的一个缺点是,如果您尝试分配具有多个属性的对象,则会出现非描述性错误消息,例如以下分配:

const animal: ShouldBeExactlyOneOfPossibleProperties = {
cat: 'a big cat',
dog: 'a small dog'
};

给出以下错误:

Type '{ cat: string; dog: string; }' is not assignable to type '({ dog?: undefined; cow?: undefined; } & { cat: string | undefined; }) | ({ cat?: undefined; cow?: undefined; } & { dog: string | undefined; }) | ({ cat?: undefined; dog?: undefined; } & { cow: string | undefined; })'.
Type '{ cat: string; dog: string; }' is not assignable to type '{ cat?: undefined; dog?: undefined; } & { cow: string | undefined; }'.
Type '{ cat: string; dog: string; }' is not assignable to type '{ cat?: undefined; dog?: undefined; }'.
Types of property 'cat' are incompatible.
Type 'string' is not assignable to type 'undefined'.(2322)

另一种方法:您可以模拟此 answer 中建议的独占联合类型.但在这种情况下,一个额外的属性被添加到对象中。

type ExactlyOne<T, TKey = keyof T> = TKey extends keyof T
? { [key in TKey]: T[TKey] } & { prop: TKey }
: never;

const animal: ExactlyOne<PossibleProperties> = {
prop: 'cat',
cat: 'a big cat'
};

Playground

关于Typescript 类型,其中对象完全由一组可能属性的单个属性组成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62158066/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com