How to declare generic function for converting to an array in TypeScript?

Viewed 17

I have a general function for wrapping anything to an array:

const ensureArray = <T,>(value?: T | T[]): T[] => {
  if (Array.isArray(value)) return value
  if (value === undefined) return []
  return [value]
}

const undef = undefined
ensureArray(undef) // result type undefined[]

const str = 'string'
ensureArray(str)  // result type string[]

const strArray = ['string']
ensureArray(strArray)  // result type string[]

interface Interface {
  [key: string]: string | string[] | number | number[]
}
const p:Interface ={a:'x'}
ensureArray(p.a)  
// types as const ensureArray: <string | number>(value?: string | number | (string | number)[] | undefined) => (string | number)[]

Is there a way to make the TypeScript deduce the function type as

(value: string | number | string[] | number[] | undefined) => string[] | number[]

?

Fiddle with the example: https://www.typescriptlang.org/play?#code/MYewdgzgLgBAppArgJzgQWcghgTxgXhgB4AVAGgD4AKANywBtE4B+ALhhJgB8OBtAXQCU7EgIIUYAbwBQMGAEsAZjCoZsOAHTyIa3LQZNBgmKigowMOoziyFy-dYL5CiMABM4i+WDhvjp8xgBWwDkC14rJn5pAF9paVBIWFcPZRd3T29faQQIFHRMPRTPQXjE6BhoZAIYAHIq7wBzWpykVF0cKirShPAKqo6a3nqoZCba6Nz8jq7Rjp7vKDhkRSxgOBgASTAllbWNmTleAGs4HHYGsEb+C9Gm7kq7q7EeMEQAWwAjZYe3r+XgnFyrAAA6sba7VbrAiSLCsWoAD1qcSm7UKnRBGiwpSAA

1 Answers

I would add an overload to the function where the return type is a conditional type.

function ensureArray<T,>(value?: T | T[]): T extends any[] ? T : T[]
function ensureArray<T,>(value?: T | T[]): T[] {
  if (Array.isArray(value)) return value
  if (value === undefined) return []
  return [value]
}

We can check if T is an array type. If it is, just return it. If not, return T[]. The overload will stop TypeScript from complaining about the return statements in the actual implementation.


Playground

Related