为什么推断类型可以转换为索引集合,而看似相同的显式类型却不能?

时间:2019-04-02 08:07:13

标签: typescript

请问有人可以解释为什么我的推断类型被接受为我更一般的集合类型的实例,而我的显式类型却未被接受吗?

我正试图:

  • 我的应用程序的一部分与定义紧密的集合(例如IParents与IBosses)一起使用。

  • 让我的应用的另一部分更一般地使用相同的对象(如IPeople)工作。

我不为我的类型不被接受为一般索引集合类型的实例而感到完全惊讶。但是我很惊讶我的推断类型被接受。我以为推断的类型将与我的显式类型相同。

推断类型也可以得到免费的索引器吗?在工具提示中描述类型时未提及。

interface IPerson {
    name: string
}

let personA: IPerson = { name: "X" }
let personB: IPerson = { name: "Y" }

// Indexed person collection
interface IPeople {
    [id: string]: IPerson
}

// Explicit person collections
interface IParents {
    mother: IPerson
    father: IPerson
}

interface IBosses {
    manager: IPerson
    director: IPerson
}

// Explicitly-typed instances

let objPeople: IPeople = {
    x: personA,
    y: personB
}

let objParents: IParents = {
    mother: personA,
    father: personB
}

let objBosses: IBosses = {
    manager: personA,
    director: personB
}

// Inferred-typed instances

// Inferred type is { mother: IPerson, father: IPerson } ??
let objInferredParents = {
    mother: personA,
    father: personB,
}

// Inferred type is { manager: IPerson, director: IPerson } ??
let objInferredBosses = {
    manager: personA,
    director: personB,
}

// I want to work elsewhere with the specific types but have this be able to process them all
function processPeople(col: IPeople) {
    // NOP
}

processPeople(objPeople)

// The explicit types are NOT assignable to IPeople
//   "Argument of type 'IParents' is not assignable to parameter of type 'IPeople'.
//      Index signature is missing in type 'IParents'."
processPeople(objParents) // ERROR
processPeople(objBosses) // ERROR

// The inferred types ARE assignable to IPeople
processPeople(objInferredParents)
processPeople(objInferredBosses)

TypeScript playground

1 个答案:

答案 0 :(得分:1)

IPeople明确允许使用任何键进行索引,因为它具有索引签名。因此,这意味着processPeople可以访问对象上不期望的任何键(例如processPeople可以访问mother上的IBosses

您可以使用通用类型参数来约束该参数以具有所有IPerson属性,无论这些属性可能是什么:

function processPeople<T extends Record<keyof T, IPerson>>(col: T) {
    // NOP
}

processPeople(objPeople)

processPeople(objParents) // OK
processPeople(objBosses) // Ok

processPeople(objInferredParents)
processPeople(objInferredBosses)