Typescript - 类型映射在泛型函数中失败

Typescript - type mapping fails inside a generic function

给定这些 Typescript 类型:

// Validation types
type Methods = 'firstName' | 'lastName' | 'email'
type Method<T> = {[K in keyof T]?: Methods }
type Row<T> = keyof T | Method<T>
type Mapping<T> = Array<Row<T>>

// Fields that will be accepted
type Fields = {
  firstName: string
  lastname: string
  e?: string
}

而这个数据:

// Data object, holding the form submission
const data: Fields = {
  firstName: 'John',
  lastname: 'Doe',
  e: 'john@example.com'
}

// Map validation methods to the data fields
const mapping: Mapping<Fields> = [
  'firstName',
  'lastname',
  {
    e: 'email'
  }
]

为什么这样做:

const validationFuncs: Method<Fields>[] = mapping.map(m => {
  return typeof m === 'string' ? { [m]: m } : m;
})

// validationFuncs[0].firstName // works

但这不是吗?

function validate<T>(mapping: Mapping<T>) {
  const validationFuncs: Method<T>[] = mapping.map(m => {
    return typeof m === 'string' ? { [m]: m } : m;
  })
}

Method<T>的值必须是Methods,只能是"firstName""lastName""email"。在您的通用示例中:

function validate<T>(mapping: Mapping<T>) {
  const validationFuncs: Method<T>[] = mapping.map(m => {
    return typeof m === 'string' ? { [m]: m } : m;
  })
}

类型 T 可以是任何类型...例如,{nope: string}。在这种情况下,keyof T"nope"validationFuncs 的声明类型是 {nope?: Methods}[]

但是如果 mapping["nope"](有效的 Mapping<{nope: string}>),那么 validationFuncs 在运行时将是 [{nope: "nope"}]。但这不是 {nope?: Methods}[],因为 validationFuncs[0].nope"nope" 而不是 undefinedMethods 的三个允许值中的任何一个。所以编译器会警告你。这一切对我来说都很有意义。


在您的非通用 "working" 示例中:

const validationFuncs: Method<Fields>[] = mapping.map(m => {
  return typeof m === 'string' ? { [m]: m } : m;
})

发生了一些奇怪的事情。 Method<Fields> 等同于

type MethodFields = { 
  firstName?: Methods
  lastname?: Methods
  e?: Methods 
}

但是TypeScript 2.6中{ [m]: m }isn't working properly because of a TypeScript bug with computed keys which might be fixed的类型检查;不确定。

编译器应该(但没有)意识到 { [m]: m } 只能保证是 {firstName:"firstName"}{lastname:"lastname"}{e:"e"},其中最后两个是不是有效的Method<Fields>元素(注意lastname中的小写"n")。相反,类型检查器将 { [m]: m } 的类型扩展为类似 { [k: string]: keyof Fields } 的类型,这显然足够宽以匹配 Method<Fields>,但我不明白如何。无论如何,它会在不应该检查的时候进行检查;这是 TypeScript 中的错误或设计限制。


在这两种情况下,您都没有以符合您声明的类型的方式实现您的代码。我不知道你的类型是否正确但实现是错误的,反之亦然,或者其他什么。我希望你现在有足够的信息来取得进展。祝你好运!