TypeScript 索引类型对象和记录之间的断开推理

uwopmtnx  于 4个月前  发布在  TypeScript
关注(0)|答案(4)|浏览(139)

TypeScript版本: 2.2.2
代码

interface Errors {
  [field: string]: {
    key: string
    message: string
  }
}

const errors: Errors = {}

function genericObjectFunction<K extends string, V>(obj: Record<K, V>): [K, V][] {
  return []
}

/*
Argument of type 'Errors' is not assignable to parameter of type 'Record<string, never>'.
Index signatures are incompatible.
Type '{ key: string; message: string; }' is not assignable to type 'never'.
*/
genericObjectFunction(errors)

尽管类型看起来大致兼容,但这是合法的:

const errorRecord: Record<string, { key: string, message: string }> = errors

预期行为:

genericObjectFunction(errors) 应该能够编译。

4ngedf3f

4ngedf3f1#

这个失败的原因是

interface Errors {
  [field: string]: {
    key: string
    message: string
  };
}

没有离散的键,所以记录是空的。 Record<K, V> 类型是通过将键Map到值来定义的,由于没有已知的值,通用示例化没有成员。
考虑

const errors = { // no explicit type, inferred type has members, still compatible with interface.
  password: {
    key: 'minimumComplexity',
    message: 'Password must contain at least one non alphanumeric character'
  }
};

function genericObjectFunction<K extends string, V>(obj: Record<K, V>): [K, V][] {
  return [];
};

const genericErrors = genericObjectFunction(errors);

编辑:

这里有一个带有解决方法的例子(注意:重载顺序很重要)

interface Errors {
  [field: string]: {
    key: string
    message: string
  }
}

const errors: Errors = {
  password: {
    key: 'minimumComplexity',
    message: 'Password must contain at least one non alphanumeric character'
  }
};

function genericObjectFunction<K extends string, V>(obj: Record<K, V>): [K, V][];
function genericObjectFunction<V>(obj: { [field: string]: V }): [string,{[P in keyof V]:V[P]}][];
function genericObjectFunction<K extends string, V>(obj: Record<string, V>): [K, V][]{
  return [];
};
const typeInferredErrors = {
  password: {
    key: 'minimumComplexity',
    message: 'Password must contain at least one non alphanumeric character'
  }
};

const genericErrorsX = genericObjectFunction(errors);
const genericErrorsY = genericObjectFunction(typeInferredErrors);
pcww981p

pcww981p2#

是的,我尝试了重载作为POC,它可以工作。只是在几十个函数上这样做有点烦人:)
我理解Record试图从显式键和值中提取信息,但两者之间是否存在简单的翻译?

laik7k3q

laik7k3q3#

我理解Record试图从显式键和值中提取信息,但两者之间是否存在简单的翻译?
可能有,但我觉得将两者混合可能会导致错误。
这也有可能是一个bug。我不相信是,但我肯定有可能犯错。

krcsximq

krcsximq4#

从v3.3.3版本开始,不再产生错误。
Playground链接:v3.1.6,有错误
Playground链接:v3.3.3,无错误
这是否应该关闭?

相关问题