Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
182 views
in Technique[技术] by (71.8m points)

Conditionally type function based on parameter value in typescript

i'm trying to make a factory for my models in Typescript using the faker package. I've manage to create a functional generic factory, like the casual package api, that receives a generic model maker, and a options to override the created model. That generic factory generates a model factory, so its a factory that generates a factory. This generated factory can receive two parameters, the first one is the amount of model that i want to make, the default value is 1 and the second parameter is the options that i want to overwrite on my models. The problem that i have is, i don't know if is possible to conditionally determinate the return type of the factory based on the quantity value automatically, such as if the quantity is one, i should return IModel but if the quantity is bigger than one i should return IModel[].

Right now I've explicit returning IModel | IModel[], and whenever i use the factories i must type the return like this:

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

My code:

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

Factory Maker

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
  }
}

My User Factory


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 }
question from:https://stackoverflow.com/questions/65647402/conditionally-type-function-based-on-parameter-value-in-typescript

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You could make factoryMaker return N extends 1 ? T : T[], where N is the quantity:

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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...