如何在 TypeScript 中将 switch 语句转换为对象字面量
How to convert switch statement to object literal in TypeScript
我正在尝试将 switch 语句转换为打字稿中的对象文字,但出现以下错误:
Argument of type 'AllowedAnimals' is not assignable to parameter of type 'never'.
The intersection 'Dog & Horse' was reduced to 'never' because property 'species' has conflicting types in some constituents.
Type 'Dog' is not assignable to type 'never'.
... 下面是示例代码。我是不是打字不正确,或者这是 Typescript 的反模式?
interface Animal{
species:string,
weight:number,
name:string
}
type AllowedAnimals = Dog |Horse
interface Dog extends Animal{
species:"dog",
hasFleas:boolean
}
interface Horse extends Animal{
species:"horse",
handsTall:number
}
const processDog = (d:Dog)=>{}
const processHorse = (h:Horse)=>{}
const userInput = "";
const a:AllowedAnimals = JSON.parse(userInput);
switch (a.species){
case "dog":
processDog(a);
break;
case "horse":
processHorse(a);
break;
default:
break;
}
const objectLiteral = {
"dog":processDog,
"horse":processHorse
}
objectLiteral[a.species](a); //<- Error
正如我在评论中所说:
Typescript 在这方面表现不错。 a
是一个值,您告诉打字稿的类型是 AllowedAnimals
,它本身就是一个联合。当你写 objectLiteral[a.species]
时,打字稿不知道 dog
或 horse
之间的哪一个会被索引,所以它不能给你关于函数参数的提示。
正如您在问题中提到的,您可以受益于 type narrowing 使用 switch 语句来完成您想要做的事情:
interface Animal{
species:string,
weight:number,
name:string
}
type AllowedAnimals = Dog |Horse
interface Dog extends Animal{
species:"dog",
hasFleas:boolean
}
interface Horse extends Animal{
species:"horse",
handsTall:number
}
const processDog = (d:Dog)=>{}
const processHorse = (h:Horse)=>{}
const process = (animal : AllowedAnimals) => {
switch(animal.species) {
case "dog":
objectLiteral[animal.species](animal);
break;
case "horse":
objectLiteral[animal.species](animal);
break;
}
}
const objectLiteral = {
"dog":processDog,
"horse":processHorse
}
const userInput = "";
const a:AllowedAnimals = JSON.parse(userInput);
process(a);
Typescript 不够聪明,无法确定 objectLiteral[a.species]
的类型取决于 a
的具体类型。它只知道 属性 访问会得到 (d: Dog) => void | (h: Horse) => void
,但是当您尝试调用它时,它需要统一参数类型,认为参数需要具有可以是传递给这些函数中的任何一个。 (a: Dog & Horse) => void
显示为 a: never
,如错误消息所述。
你可以通过显式转换作弊:
(objectLiteral[a.species] as (a: AllowedAnimal) => void)(a);
这样你就可以满足类型检查器的要求了。我不知道这是否是个好主意——你得到的检查可能不如 switch
.
type process<X extends Animal> = (a: X) => void
const processDog: process<Dog> = _=>{}
const processHorse: process<Horse> = _=>{}
const objectLiteral: {
[p in AllowedAnimals['species']]: process<AllowedAnimals & {species: p}>
} = {
"dog": processDog,
"horse": processHorse
};
let a: AllowedAnimals = null as any;
(objectLiteral[a.species] as process<AllowedAnimals>)(a);
我正在尝试将 switch 语句转换为打字稿中的对象文字,但出现以下错误:
Argument of type 'AllowedAnimals' is not assignable to parameter of type 'never'.
The intersection 'Dog & Horse' was reduced to 'never' because property 'species' has conflicting types in some constituents.
Type 'Dog' is not assignable to type 'never'.
... 下面是示例代码。我是不是打字不正确,或者这是 Typescript 的反模式?
interface Animal{
species:string,
weight:number,
name:string
}
type AllowedAnimals = Dog |Horse
interface Dog extends Animal{
species:"dog",
hasFleas:boolean
}
interface Horse extends Animal{
species:"horse",
handsTall:number
}
const processDog = (d:Dog)=>{}
const processHorse = (h:Horse)=>{}
const userInput = "";
const a:AllowedAnimals = JSON.parse(userInput);
switch (a.species){
case "dog":
processDog(a);
break;
case "horse":
processHorse(a);
break;
default:
break;
}
const objectLiteral = {
"dog":processDog,
"horse":processHorse
}
objectLiteral[a.species](a); //<- Error
正如我在评论中所说:
Typescript 在这方面表现不错。 a
是一个值,您告诉打字稿的类型是 AllowedAnimals
,它本身就是一个联合。当你写 objectLiteral[a.species]
时,打字稿不知道 dog
或 horse
之间的哪一个会被索引,所以它不能给你关于函数参数的提示。
正如您在问题中提到的,您可以受益于 type narrowing 使用 switch 语句来完成您想要做的事情:
interface Animal{
species:string,
weight:number,
name:string
}
type AllowedAnimals = Dog |Horse
interface Dog extends Animal{
species:"dog",
hasFleas:boolean
}
interface Horse extends Animal{
species:"horse",
handsTall:number
}
const processDog = (d:Dog)=>{}
const processHorse = (h:Horse)=>{}
const process = (animal : AllowedAnimals) => {
switch(animal.species) {
case "dog":
objectLiteral[animal.species](animal);
break;
case "horse":
objectLiteral[animal.species](animal);
break;
}
}
const objectLiteral = {
"dog":processDog,
"horse":processHorse
}
const userInput = "";
const a:AllowedAnimals = JSON.parse(userInput);
process(a);
Typescript 不够聪明,无法确定 objectLiteral[a.species]
的类型取决于 a
的具体类型。它只知道 属性 访问会得到 (d: Dog) => void | (h: Horse) => void
,但是当您尝试调用它时,它需要统一参数类型,认为参数需要具有可以是传递给这些函数中的任何一个。 (a: Dog & Horse) => void
显示为 a: never
,如错误消息所述。
你可以通过显式转换作弊:
(objectLiteral[a.species] as (a: AllowedAnimal) => void)(a);
这样你就可以满足类型检查器的要求了。我不知道这是否是个好主意——你得到的检查可能不如 switch
.
type process<X extends Animal> = (a: X) => void
const processDog: process<Dog> = _=>{}
const processHorse: process<Horse> = _=>{}
const objectLiteral: {
[p in AllowedAnimals['species']]: process<AllowedAnimals & {species: p}>
} = {
"dog": processDog,
"horse": processHorse
};
let a: AllowedAnimals = null as any;
(objectLiteral[a.species] as process<AllowedAnimals>)(a);