在通用函数中,Typescript - 类型映射失败

时间:2017-10-26 15:06:33

标签: javascript typescript typescript2.0

鉴于这些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;
  })
}

Why?

1 个答案:

答案 0 :(得分:2)

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的三个允许值中的任何一个。所以编译器会警告你。这一切都对我有意义。

在非通用的“工作”示例中:

const validationFuncs: Method<Fields>[] = mapping.map(m => {
  return typeof m === 'string' ? { [m]: m } : m;
})
发生了一些奇怪的事情。 Method<Fields>相当于

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

但是{ [m]: m } isn't working properly because of a TypeScript bug with computed keys的类型检查,其中可能在TypeScript 2.6中为fixed;不确定。

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

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