繁体   English   中英

使用 TypeScript 使函数的返回类型取决于其参数?

[英]Make return type of function depends on its arguments with TypeScript?

我有一个函数返回一个承诺,它可以是两种类型之一:

async profilesAll(
    ids: readonly number[],
    profileType: ProfileType.Staff | ProfileType.Pupil,
  ): Promise<(DatabaseSchema.staffProfiles | DatabaseSchema.pupilProfiles)[]> {
   // lots of logic here
}

在其他地方我正在调用这个函数。 otherFunction的返回类型是一个DatabaseSchema.pupilProfiles数组

const otherFunction = () => {
    const results = await ctx.models.room.profilesAll(
        [root.id],
        ProfileType.Pupil,
      );
    return results;
}

TypeScript 会抛出错误,因为它认为返回类型可以是DatabaseSchema.staffProfilesDatabaseSchema.pupilProfiles 然而实际上, profilesAll的逻辑阻止了这一点。

我怎样才能消除这个错误? 我可以让profilesAll的返回类型取决于profileType参数吗? 我查看了条件类型,但我只能看到它们扩展类型的示例,而不是根据需要使用函数参数。

您应该使用重载:

async function profilesAll(ids: number[], profileType: ProfileType.Pupil): Promise<(DatabaseSchema.pupilProfiles)[]>
async function profilesAll(ids: number[], profileType: ProfileType.Staff): Promise<(DatabaseSchema.staffProfiles)[]>
async function profilesAll(
  ids: readonly number[],
  profileType: ProfileType.Staff | ProfileType.Pupil,
): Promise<DatabaseSchema.staffProfiles[]> | Promise<DatabaseSchema.pupilProfiles[]> {
   // lots of logic here
}

我认为您不能根据输入参数动态修改返回类型。 但是,在这种特定情况下,您可以通过显式定义来指定otherFunction的返回类型。

const otherFunction = (): DatabaseSchema.pupilProfiles => { ... }

这样你的otherFunction返回类型不再是DatabaseSchema.staffProfiles | DatabaseSchema.pupilProfiles DatabaseSchema.staffProfiles | DatabaseSchema.pupilProfiles但仅限DatabaseSchema.pupilProfiles

您可以为此声明使用函数/方法重载。

方法

class Foo {
  //option 1:
  async profilesAll(ids: readonly number[], profileType: ProfileType.Staff): Promise<DatabaseSchema.staffProfiles[]>; 
  //option 2:
  async profilesAll(ids: readonly number[], profileType: ProfileType.Pupil): Promise<DatabaseSchema.pupilProfiles[]>; 
  //implementation:
  async profilesAll(ids: readonly number[], profileType: ProfileType.Staff | ProfileType.Pupil): Promise<(DatabaseSchema.staffProfiles | DatabaseSchema.pupilProfiles)[]> {
      if (profileType === ProfileType.Staff) return getStaff(ids);
      
      return getPupils(ids);
  }
}

请注意,您首先需要重载签名,然后第三个实现签名应该是它们的合并。 在此处查看有关重载的更多信息

这将允许您进行类型安全调用:

declare const instance: Foo;
//OK:
const pupils = await instance.profilesAll([1, 2, 3], ProfileType.Pupil);
//OK:
const staff  = await instance.profilesAll([1, 2, 3], ProfileType.Staff);
//Error - return type is not pupilProfiles:
const wrong: DatabaseSchema.pupilProfiles[]  = await instance.profilesAll([1, 2, 3], ProfileType.Staff);

游乐场链接

功能

使用函数并重载它们是类似的,但在这种情况下你不会有一个类:

//option 1:
async function profilesAll(ids: readonly number[], profileType: ProfileType.Staff): Promise<DatabaseSchema.staffProfiles[]>;
//option 2:
async function profilesAll(ids: readonly number[], profileType: ProfileType.Pupil): Promise<DatabaseSchema.pupilProfiles[]>;
//implementation:
async function profilesAll(ids: readonly number[], profileType: ProfileType.Staff | ProfileType.Pupil): Promise<(DatabaseSchema.staffProfiles | DatabaseSchema.pupilProfiles)[]> {
    if (profileType === ProfileType.Staff) return getStaff(ids);
    
    return getPupils(ids);
}

/* ... */

//OK:
const pupils = await profilesAll([1, 2, 3], ProfileType.Pupil);
//OK:
const staff  = await profilesAll([1, 2, 3], ProfileType.Staff);
//Error - return type is not pupilProfiles:
const wrong: DatabaseSchema.pupilProfiles[]  = await profilesAll([1, 2, 3], ProfileType.Staff);

游乐场链接

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM