typescript 如何在向对象添加特定类型的附加键时引发类型错误[duplicate]

ifsvaxew  于 2023-02-20  发布在  TypeScript
关注(0)|答案(2)|浏览(113)
    • 此问题在此处已有答案**:

Enforce that an array is exhaustive over a union type(2个答案)
In TypeScript, how to get the keys of an object type whose values are of a given type?(2个答案)
2天前关闭。
假设我有MyType类型

type MyType = {
  foo: number;
  bar: string;
  baz: string;
}

我想定义一个数组requiredFields,它包含MyType的所有键,这些键的值是指定的类型T。这样,如果一个类型为T的附加键后来被添加到MyType中,requiredFields应该抛出一个类型错误,因为新的键现在丢失了。
这可能类似于:

const numberFields: ExtractKeysByType<MyType, number> = ['foo'] // ✅
const stringFields: ExtractKeysByType<MyType, string> = ['bar'] // ❌ error - missing "baz"
whlutmcx

whlutmcx1#

把另外两个答案结合起来,我得到了我想要的结果,但是后一个答案前面有一个大大的"不要这样做"警告,所以请采取同样的预防措施:

步骤1:How to extract keys of certain type from object

type ExtractKeyUnionByType<Obj, Type> = {
  [Key in keyof Obj]: Obj[Key] extends Type ? Key : never
}[keyof Obj]

这与我所寻找的很接近,但是返回一个联合类型而不是元组类型。

ExtractKeyUnionByType<MyType, string> // => 'bar' | 'baz'

如果要包含可选类型,请将undefined添加到联合中

type MyType = {
  foo?: number;
  bar: string;
  baz?: string;
  obj: MyOtherType
}

ExtractKeyUnionByType<MyType, string | undefined> // => 'bar' | 'baz' | undefined

第二步:How to transform union type to tuple type(提醒,作者 * 真的 * 不希望您使用此代码)

一个三个三个一个
现在您可以强类型化元组,这样,如果您添加任何额外的属性或删除任何属性,它将抛出错误。

const requiredFields: BarAndBazTuple = ['bar', 'baz'] // ✅

const missing: BarAndBazTuple = ['bar']               // ❌ error
const extra: BarAndBazTuple = ['bar', 'baz', 'other'] // ❌ error
zy1mlcev

zy1mlcev2#

T类型的MyType的键从数组中丢失时抛出类型错误的目标可以更容易地实现,方法是首先用所讨论的键定义一个对象intermediateObj,然后使用Object.keys()将该对象转换为数组requiredFields
通过利用联合类型和Record,当缺少键时可以抛出错误;与Array<UnionType>相反,Array<UnionType>仅在添加了不正确的属性时才出错(在丢失属性时不会出错)。
首先是两个实用程序类型,第一个是从this wonderful other answer借用的,第二个修改了第一个,使其包含可选属性。

type ExtractRequiredKeysByType<Obj, Type> = {
  [Key in keyof Obj]: Obj[Key] extends Type ? Key : never
}[keyof Obj]

type ExtractKeysByType<Obj, Type> = NonNullable<
  ExtractRequiredKeysByType<Obj, Type | undefined>
>

ExtractKeysByType可用于定义必须包含MyType中所有string键的对象

type StringKeys = ExtractKeysByType<MyType, string>

const intermediateObj: Record<StringKeys, true> = {
  bar: true,
  baz: true,
}

最后,可以通过Object.keys()将中间对象转换为所需的数组

const requiredFields = Object.keys(offerTermDateFieldsObj) as StringKeys[]

现在,如果有人向MyType添加另一个字符串值anotherString,则intermediateObj的定义中将抛出错误
类型{ bar: true; baz: true }中缺少属性'anotherString',但类型Record<StringKeys, true>中需要该属性。

相关问题