简体   繁体   English

typescript 可以检查Enum 的每个Record 值吗?

[英]Can typescript check every Record value of Enum?

Typescript is beautiful, and I love to write on typescript cause I can just write Typescript 很漂亮,我喜欢在 typescript 上写,因为我可以写

enum Test {
    some = 'some',
    another = 'another',
}

const test: Record<Test, string> = {
    some: 'string'
}

then typescript asks me to type every key value from Test as the key of my test object然后 typescript 要求我键入Test中的每个键值作为我测试的键 object

Property 'another' is missing in type '{ some: string;类型 '{ some: string; 中缺少属性 'another' }' but required in type 'Record<Test, string>' }' 但在类型 'Record<Test, string>' 中需要

But if I want to write an opposite operation (like parse/stringify), I want to be sure that I don't miss some Test as values of Record但是如果我想写一个相反的操作(比如解析/字符串化),我想确保我不会错过一些测试作为记录的值

enum Test {
    some = 'some',
    another = 'another',
}
const test: Record<string, Test> = {
    some: Test.some
}

But typescript assume that it is correct.但是 typescript 假设它是正确的。

I would like to throw some error by typescript.我想通过 typescript 抛出一些错误。

Is there any way in typescript to check every Record value of Enum? typescript有什么方法可以检查Enum的每个Record值吗?

TypeScript doesn't really have the idea of "exhaustive property types", but you could write a generic type along with a helper function to validate that a given value behaves as you like. TypeScript 并没有真正的“详尽属性类型”的想法,但您可以编写一个泛型类型以及一个帮助器 function 来验证给定值的行为是否如您所愿。 For example:例如:

const exhaustive = <V,>() => <T extends Record<keyof T, V>>(
    t: { [K in keyof T]: [V] extends [T[keyof T]] ? T[K] : Exclude<V, T[keyof T]> }
) => t;

This is a curried function where you manually specify the value type V you'd like to "exhaust", and it outputs another generic function that does the check:这是一个curried function,您可以在其中手动指定要“耗尽”的值类型V ,它会输出另一个进行检查的通用 function:

enum Test {
    some = 'some',
    another = 'another',
}   
const exhaustiveTest = exhaustive<Test>()

(The reason you need to use two functions like that is because TypeScript doesn't let you manually specify a generic type argument while inferring another one; there is an open feature request for this at microsoft/TypeScript#26242 and the various workarounds including currying are discussed in Typescript: infer type of generic after optional first generic ) (你需要使用两个这样的函数的原因是因为 TypeScript 不允许你在推断另一个类型参数时手动指定一个泛型类型参数;在microsoft/TypeScript#26242有一个开放的功能请求和各种解决方法,包括 currying在Typescript 中讨论:在可选的第一个泛型之后推断泛型类型


When you call exhaustiveTest() it will return its input, but a compiler error will occur if you are missing any of the values in Test :当您调用exhaustiveTest()时,它将返回其输入,但如果您缺少Test中的任何值,则会发生编译器错误:

const test = exhaustiveTest({
    abc: Test.some,
    def: Test.another
}); // okay

const badTest = exhaustiveTest({
    abc: Test.some // error! Type 'Test.some' is not assignable to type 'Test.another'
})

Hooray, that's what you wanted!万岁,这就是你想要的!


The way it works is that the call to exhaustiveTest() infers the type argument T to be the type passed in as the function argument t , but it checks it against the mapped type { [K in keyof T]: [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> }它的工作方式是调用exhaustiveTest()推断类型参数T是作为 function 参数t传入的类型,但它根据映射类型检查它{ [K in keyof T]: [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> } { [K in keyof T]: [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> } . { [K in keyof T]: [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> } Each property is the conditional type [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]>每个属性都是条件类型[Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> . [Test] extends [T[keyof T]]? T[K]: Exclude<Test, T[keyof T]> That means: if every value of type Test can be assigned to one of the property types of T , then each property of T is just fine as itself (the indexed access type T[K] );这意味着:如果类型Test的每个值都可以分配给 T 的属性类型之一,那么T的每个属性都和它本身一样好( 索引访问类型T T[K] ); otherwise, it should be Exclude<Test, T[keyof T]> using the Exclude<T, U> utility type to filter out all the properties of T from Test to get just the missed values, so that the error message will mention these missing values.否则,它应该是Exclude<Test, T[keyof T]>使用Exclude<T, U>实用程序类型Test中过滤掉T的所有属性以获取遗漏的值,以便错误消息将提及这些缺失值。

As a concrete case, if T is {abc: Test.some; def: Test.another}作为一个具体的例子,如果T{abc: Test.some; def: Test.another} {abc: Test.some; def: Test.another} , then T[keyof T] is Test.some | Test.another {abc: Test.some; def: Test.another} ,那么T[keyof T]就是Test.some | Test.another Test.some | Test.another , which is the same as Test , and so the mapped type is just {abc: Test.some; def: Test.another} Test.some | Test.another ,与Test相同,因此映射类型只是{abc: Test.some; def: Test.another} {abc: Test.some; def: Test.another} , and it type checks. {abc: Test.some; def: Test.another} ,然后输入检查。 But if T is just {abc: Test.some} , then T[keyof T] is just Test.some , which is missing thing from Test .但是如果T只是{abc: Test.some} ,那么T[keyof T]就是Test.some ,这是Test中缺少的东西。 And so the mapped type is {abc: Test.another} , and it fails to type check, complaining about the missing thing.所以映射类型是{abc: Test.another} ,它无法进行类型检查,抱怨丢失的东西。

Playground link to code 游乐场代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM