打字稿有条件地需要参数

时间:2021-07-18 22:25:32

标签: typescript

我想编写一个接受一些参数的函数,它们应该是可选的,但如果它们存在,那么我希望其他参数是必需的。

这是一个非常愚蠢的例子:

type PersonInfo = {
  name: string; 
  age: number; 
  pets?: boolean; 
  petNames?: string[]; 
}
const recordPersonInfo = (options: PersonInfo) => {
  database.save(options); 
}

所以 pets 属性可以省略,但如果它是 true 那么我希望 petNames 是必需的。我如何告诉 Typescript 这样做?

2 个答案:

答案 0 :(得分:3)

你可以使用联合类型:pets 属性是一个判别式,所以如果你写 if(options.pets) 那么在 if 块内,options 将被缩小到确定拥有 petNames 属性。

type PersonInfo = {
  name: string; 
  age: number;
} & ({
  pets?: false;
} | {
  pets: true; 
  petNames: string[]; 
})

const recordPersonInfo = (options: PersonInfo) => {
  database.save(options); 
}

答案 1 :(得分:0)

利用函数重载,你可以这样做:

type PersonInfoWithPets = PersonInfo & { pets: true; petNames: string[] };
type PersonInfoWithoutPets = PersonInfo & { pets?: false; petNames?: undefined };


function recordPersonInfo(options: PersonInfoWithPets): void;
function recordPersonInfo(options: PersonInfoWithoutPets): void;
function recordPersonInfo(options: PersonInfo): void {

}

recordPersonInfo({
    name: 'name',
    age: 0,
});
recordPersonInfo({
    name: 'name',
    age: 0,
    pets: false,
});
recordPersonInfo({
    name: 'name',
    age: 0,
    pets: true,
    petNames: [],
});
// This errors because `pets` but no `petNames`
recordPersonInfo({
    name: 'name',
    age: 0,
    pets: true,
});
// This errors because `petNames` but no `pets`
recordPersonInfo({
    name: 'name',
    age: 0,
    petNames: ['hi'],
});
// NOTE: This also errors because `pets` is a boolean here, not strictly true/false
recordPersonInfo(null! as PersonInfo);

老实说,TypeScript 并没有为此提供完美的解决方案。在这种特定情况下,您当然可以说“petNames 的存在(和空虚)应该取代对 pets 字段的需要”。在这种情况下,我们避开了两个重载,但更复杂的情况可能会导致需要更多的重载。

当然,您可以正确地记录函数,如果仍然给出错误的输入,则抛出错误。