Typescript:类型不可分配给泛型类型的实例-两者看起来相同


export type Animal<T extends Kind> = T extends "cat"
? CatData<T>
: DogData<"dog">
export type Kind = "cat" | "dog"
type CatData<T extends "cat"> = {
kind: T
someData: number[]
}
type DogData<T extends "dog"> = {
kind: T
someData: string[]
}
const fun = <T extends Kind>(kind: T): Animal<T> => {
switch (kind) {
case "cat":
return {
kind,
someData: [33],
}
default:
return {
kind,
someData: ["data"],
}
}
}

对于上面的代码,我在switch语句中得到了两个关于这两种情况的错误。两个错误相同:

test.ts    24   7 error    2322   Type '{ kind: T; someData: string[]; }' is not assignable to type 'Animal<T>'. (lsp)

我不明白为什么这些类型不能分配给动物。我可能遗漏了一些内容,但它们看起来像是函数参数提供的带有T的泛型Animal类型的实例。

上面的代码出了什么问题?

fun中,您希望缩小类型T,从而缩小Animal<T>,但实际上只是缩小参数kind的类型。检查kind等于(例如("cat"并不一定意味着T类型的其他变量,包括函数的返回值。这在一定程度上是TypeScript的限制。

这里需要的习惯用法是使用索引访问类型的KindAnimal类型的映射。这将清理类型的结构,但它并没有解决上述限制。函数内部的包装器虽然不是很优雅,但可以解决这个问题。以下是全部内容:

interface KindMap {
"cat": CatData
"dog": DogData
}
export type Kind = keyof KindMap
export type Animal<T extends Kind> = KindMap[T]
type CatData = {
kind: "cat"
someData: number[]
}
type DogData = {
kind: "dog"
someData: string[]
}
const fun = <T extends Kind>(kind: T): Animal<T> => {
return ((): KindMap[Kind] => {
switch (kind) {
case "cat":
return {
kind,
someData: [33],
}
default:
return {
kind,
someData: ["data"],
}
}
}) () as Animal<T>;
}
console.log(fun("cat")) // {"kind":"cat","someData":[33]}
console.log(fun("dog")) // {"kind":"dog","someData":["data"]}
// console.log(fun("sphinx")) // Argument of type '"sphinx"' is not assignable to parameter of type 'keyof KindMap'.(2345)

(TypeScript游乐场链接(

最新更新