【问题标题】:Conditionally type function based on parameter value in typescript根据打字稿中的参数值有条件地键入函数
【发布时间】:2021-01-10 09:13:21
【问题描述】:

我正在尝试使用 faker 包在 Typescript 中为我的模型制作工厂。我已经设法创建了一个功能性通用工厂,例如休闲包 api,它接收通用模型制造商,以及覆盖创建模型的选项。该通用工厂生成模型工厂,因此它是生成工厂的工厂。这个生成的工厂可以接收两个参数,第一个是我想要制作的模型数量,默认值是 1,第二个参数是我想在我的模型上覆盖的选项。我遇到的问题是,我不知道是否可以根据数量值自动有条件地确定工厂的返回类型,例如如果数量是一,我应该返回IModel,但如果数量是大于 1 我应该返回 IModel[]

现在我已经明确返回 IModel | IModel[],每当我使用工厂时,我都必须像这样输入返回:

jest.spyOn(registerUserStub, 'execute').mockResolvedValueOnce(userFactory(1) as IUserModel)

我的代码:

// My User Model
export type IUserModel = {
  id: string,
  name: string,
  email: string,
  password: string,
  active: boolean,
  confirmed: boolean
}

工厂制造商

import { DeepPartial } from 'utility-types'

export function factoryMaker<T = any> (objMaker: (options?: DeepPartial<T>) => T): (quantity: number, options?: DeepPartial<T>) => T | T[] {
  return (quantity, options) => {
    const entitiesArray = new Array(quantity).fill(null).map(() => objMaker(options))
    return quantity === 1 ? entitiesArray[0] : entitiesArray
  }
}

我的用户工厂


import { DeepPartial } from 'utility-types'
import faker from 'faker'

import { IUserModel } from '../models'
import { factoryMaker } from './factoryMaker'

type OptionsType = DeepPartial<IUserModel>

function makeUser (options?: OptionsType):IUserModel {
  return {
    id: faker.random.uuid(),
    password: faker.random.uuid(),
    email: faker.internet.email(),
    name: faker.name.findName(),
    confirmed: options.confirmed !== undefined ? options.confirmed : true,
    active: true,
    ...options
  }
}

const userFactory = factoryMaker<IUserModel>(makeUser)

export { userFactory }

【问题讨论】:

    标签: typescript


    【解决方案1】:

    你可以让factoryMaker返回N extends 1 ? T : T[],其中N是数量:

    export function factoryMaker<T = any>(
      objMaker: (options?: DeepPartial<T>) => T
    ): <N extends number>(
      quantity: N,
      options?: DeepPartial<T>
    ) => N extends 1 ? T : T[] {
      return <N extends number>(
        quantity: N,
        options?: DeepPartial<T>
      ): N extends 1 ? T : T[] => {
        const entitiesArray = new Array(quantity).fill(null).map(() => objMaker(options))
        return (quantity === 1 ? entitiesArray[0] : entitiesArray) as N extends 1 ? T : T[]
      }
    }
    
    // ...
    
    // IUserModel
    const oneUser = userFactory(1)
    
    // IUserModel[]
    const twoUsers = userFactory(2)
    
    // IUserModel | IUserModel[]
    const oneOrTwoUsers = userFactory(Math.random() > 0.5 ? 1 : 2)
    

    【讨论】:

    • 嘿,谢谢,这很有帮助。在发布之前,我尝试过查看文档中的条件输入,但我发现 extends 语法很难理解。但是你的回答对我来说很清楚。 :)
    猜你喜欢
    • 1970-01-01
    • 2022-01-18
    • 2019-09-02
    • 2019-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多