gpt4 book ai didi

typescript - 如何在 TypeScript 中键入具有已知和未知键的对象

转载 作者:搜寻专家 更新时间:2023-10-30 20:42:23 25 4
gpt4 key购买 nike

我正在寻找一种方法来为以下具有两个已知键和一个具有已知类型的未知键的对象创建 TypeScript 类型:

interface ComboObject {
known: boolean
field: number
[U: string]: string
}

const comboObject: ComboObject = {
known: true
field: 123
unknownName: 'value'
}

该代码不起作用,因为 TypeScript 要求所有属性都匹配给定索引签名的类型。但是,我不想使用索引签名,我想键入一个我知道其类型但不知道其名称的字段。

到目前为止,我唯一的解决方案是使用索引签名并设置所有可能类型的联合类型:

interface ComboObject {
[U: string]: boolean | number | string
}

但这有很多缺点,包括在已知字段上允许不正确的类型以及允许任意数量的未知键。

有更好的方法吗? TypeScript 2.8 条件类型有帮助吗?

最佳答案

你自找的。

让我们进行一些类型操作来检测给定类型是否为联合。它的工作方式是使用 distributive条件类型的属性将联合展开到成分,然后注意每个成分都比联合窄。如果这不是真的,那是因为工会只有一个组成部分(所以它不是工会):

type IsAUnion<T, Y = true, N = false, U = T> = U extends any
? ([T] extends [U] ? N : Y)
: never;

然后用它来检测给定的 string 是否type 是单个字符串文字(因此:不是 string ,不是 never ,也不是联合):

type IsASingleStringLiteral<
T extends string,
Y = true,
N = false
> = string extends T ? N : [T] extends [never] ? N : IsAUnion<T, N, Y>;

现在我们可以开始处理您的特定问题。定义 BaseObject作为 ComboObject 的一部分您可以直接定义:

type BaseObject = { known: boolean, field: number };

并为错误消息做准备,让我们定义一个 ProperComboObject这样当你搞砸时,错误会给出一些关于你应该做什么的提示:

interface ProperComboObject extends BaseObject {
'!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!': string
}

主菜来了。 VerifyComboObject<C>接受类型 C如果它符合您想要的ComboObject,则原封不动地退回类型;否则返回 ProperComboObject (它也不符合)错误。

type VerifyComboObject<
C,
X extends string = Extract<Exclude<keyof C, keyof BaseObject>, string>
> = C extends BaseObject & Record<X, string>
? IsASingleStringLiteral<X, C, ProperComboObject>
: ProperComboObject;

它通过剖析 C 来工作进入BaseObject和其余的键 X .如果C不匹配 BaseObject & Record<X, string> ,那么你就失败了,因为这意味着它要么不是 BaseObject ,或者它是一个额外的非 string特性。然后,它通过检查 X 确保 正好有一个 剩下的 key 。与 IsASingleStringLiteral<X> .

现在我们创建一个辅助函数,它要求输入参数匹配 VerifyComboObject<C> , 并返回不变的输入。如果您只想要正确类型的对象,它可以让您尽早发现错误。或者您可以使用签名来帮助使您自己的函数需要正确的类型:

const asComboObject = <C>(x: C & VerifyComboObject<C>): C => x;

让我们测试一下:

const okayComboObject = asComboObject({
known: true,
field: 123,
unknownName: 'value'
}); // okay

const wrongExtraKey = asComboObject({
known: true,
field: 123,
unknownName: 3
}); // error, '!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!' is missing

const missingExtraKey = asComboObject({
known: true,
field: 123
}); // error, '!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!' is missing

const tooManyExtraKeys = asComboObject({
known: true,
field: 123,
unknownName: 'value',
anAdditionalName: 'value'
}); // error, '!!!ExactlyOneOtherStringPropertyNoMoreNoLess!!!' is missing

第一个会根据需要进行编译。最后三个因与额外属性的数量和类型有关的不同原因而失败。错误消息有点含糊,但这是我能做的最好的了。

您可以在 the Playground 中查看运行中的代码.


同样,我认为我不建议将其用于生产代码。我喜欢玩类型系统,但这个感觉特别好complicated and fragile ,我不想对任何 unforeseen consequences 负责.

希望对你有帮助。祝你好运!

关于typescript - 如何在 TypeScript 中键入具有已知和未知键的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49969390/

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